I have a table like this
<table>
<tr id="row-one" class="item-row">
<td class="price"></td>
<td><input type="text" class="quantity" value="" /></td>
</tr>
<tr id="row-two" class="item-row">
<td class="price"></td>
<td><input type="text" class="quantity" value="" /></td>
</tr>
<tr id="subtotal">
<td id="subtotal"></td>
<td id="subquantity"></td>
</tr>
</table>
That I am manipulating with this backbone js code
<script type="text/javascript">
jQuery(document).ready(function($){
var Item = Backbone.Model.extend({
initialize: function(){
},
defaults: {
price: 0,
quantity: 0
}
});
var ItemsCollection = Backbone.Collection.extend({
model : Item,
subquantity: function(){
subquantity = 0;
this.each(function(item){
subquantity += item.get('quantity');
});
return subquantity;
}
});
var ItemView = Backbone.View.extend({
events: {
"change .quantity": "updateQuantity"
},
render: function(){
alert('render');
},
updateQuantity: function(){
this.model.set({quantity: this.$('.quantity').val()});
console.log(this.model.get('quantity'));
}
});
var totals = new ItemsCollection();
var item_one = new Item({ price:1,quantity:10 });
var item_two = new Item({ price:1,quantity:20 });
totals.add(item_one);
totals.add(item_two);
var view_one = new ItemView({model:item_one,el:'.item-row'});
})
</script>
My questions are.
1) So far I can manage one row, that's fine. But then I want to manage the second row. Do I just instantiate another instance of ItemView
? Or can I use one ItemView
instance to manage multiple Models
? Or better yet, with the Collection
2) I am using the Collection
to manage the subtotals and subquantity. Do I create a separate view to manage those fields in the DOM? Or should I just update them inside the collection?
If anyone has any other tips I would love to hear it. This is my first time with backbone, so I just want as much info as possible. Thanks!
As with most Backbone questions, there isn't a "right" answer to this - you'll need to figure out the approach that works best for you, which will depend in part on how complex your application is likely to get.
The main thing that seems odd to me in your setup is that you've hard-coded your table to list two items - my guess is that, if you're using Backbone to begin with, you probably will be pulling a list of items from the server via AJAX and then populating the table with that list. In that case, usually you'd actually create the DOM for each row in the ItemView
class:
var ItemView = Backbone.View.extend({
// there are many different ways to do this, here's one
tagName: 'tr',
className: 'item-row',
// make an Underscore template for the inner HTML
template: _.template(
'<td class="price"><%= price %></td>' +
'<td><input type="text" class="quantity" value="<%= quantity %>" /></td>'
),
render: function(){
// this.el is already set to a tr.item-row DOM element
$(this.el).html(
// fill in the template with model attributes
this.template(this.model.toJSON())
);
// allows chaining
return this;
}
// ... now your events and handler as written
});
This gives you an ItemView
which, when rendered, has the rendered element you want to insert available once you call .render()
. Depending on your setup, you might call this.render()
right away in an initialize()
function, or you might fetch more data asynchronously and then call render()
in the callback. Either way, you have one view instance tied to one model. To manage multiple models, I might have another View class to hold the collection, which would be responsible for instantiating child ItemView
instances:
var ItemsView = Backbone.View.extend({
el: '#myTable',
render: function() {
var tableView = this;
// instantiate and render children
this.collection.each(function(item) {
var itemView = new ItemView({ model: item });
$(tableView.el).append(itemView.render().el);
});
}
});
Then in the main body of your code, all you need to do is pass the collection to your parent view, and render it:
var tableView = new ItemsView({ collection: totals });
There's a lot more to add here, most of it dealing with asynchronously fetching, rendering, and refreshing data from the server, but hopefully this gives you a basic idea of the approach. Again, however, I should emphasize that this is just one way to do things - you could, for example, build the same app with only the ItemsView
class, making it responsible for rendering all of the items itself. But the approach of using one view to manage the collection plus child views to manage the models keeps things nicely separate, and helps to minimize complexity as your app gets bigger.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With