Reputation: 4908
I have a table, its rows are models in collection, each row have two columns with inputs, rate per hour and hours, model also have attribute total
, which is basically just rate_per_hour*hours
, and it's being updated as user changes hours or rate per hour. You can add new rows and delete them as well. This, I believe, I managed to do the right backbone way.
Now first part I'm not sure about, I need to have a div which contains sums of hours and total, I've also managed to do this, using a function (which basically just loops thru models in collection, sums their attributes and then updates my div using jquery), change events on models, after setting the new attributes, are calling this function. It's outside all views/collections/models. Not sure if this is the proper way of doing this, but it works.
Now the worst part where I failed miserably, realized my code was probably wrong from the very beginning. Under that div with totals is another input, called discount, what it is supposed to do is count discount percentage ((value of discount/my total sum)*100)
, and then update the rates in table so it shows both the old one and the one with discount applied.
What I don't get is how should I connect the bottom part (totals and discount - see screenshot) with the upper part, should the bottom part be another model, with attributes total, discount and hours, and have it's own view instead of being a simple div? But then how would it work, how could one model (discount), affect models in the collection, and vice versa, adding a row would need to affect totals and discount percent?
Here's screenshot of how it's supposed to work from a working jquery-only version where I didn't use backbone yet.
Will post code if requested as well, but it's now kind of bloated with my attempts to solve it by using jquery events, my own simple objects containing those totals and shizzle wizzle.
Upvotes: 0
Views: 451
Reputation: 2399
It seems like what you're getting at is an issue with modeling your data. Sometimes it helps to take a step back and ask yourself "what are the things i'm working with?".
It seems like each of the rows you mention represents an 'activity' (each with a name, and rate). You also have a collection of these activities, which is good. Now you could ask, "what kind of thing does this entire piece of ui (represented by the screenshot in it's entirety) represent?". If we called this piece of ui an ActivitiesView, it could listen for UI interaction (changing of the fields) which would update the collection. Once the collection changes, it triggers the view to re-render with the updated totals.
In this example, the discount field on the collection is just a convenience and used by the collection to update it's children.
var Activity = Backbone.Model.extend({
defaults: { discount: 0 }
});
var ActivityCollection = Backbone.Collection.extend({
initialize: function () {
this.on("change:discount", this.updateDiscounts, this);
},
model: activity,
totalAmount: function () { /* ...iterate over items, return total amount, factoring in total */ },
totalHours: function () { /* ...iterate over items, return total hours... */ },
updateDiscounts: function (discount) { /* ...iterate over items, updating each item's discount */}
});
var ActivitiesView = Backbone.View.extend({
events: {
"change input.discount": "applyDicsounts"
},
initialize: function() {
this.listenTo(this.collection, "change", this.render);
this.listenTo(this.model, "change", this.render);
}
render: function() {
this.$el.find('.totalAmount').text(this.collection.totalAmount());
this.$el.find('.totalHours').text(this.collection.totalHours());
},
applyDicsounts: function (e) {
var new_discount = e.target.value; // should probably validate this
this.collection.set({ discount: new_discount });
}
});
var myCollection = new ActivityCollection();
var myActivitiesView = new ActivitiesView({ collection: myCollection });
Upvotes: 1