Question

Scenario: I have multiple Models in a Collection with a view for each Model and a Parent View for the Collection.

Handlebar Template for HTML:

<div id="contentarea">
    <div class="news">
        <div> {{ModelItem.text}} </div>
        <span>Number of likes: {{ModelItem.likes}} </span>
        <span>Number of dislikes: {{ModelItem.dislikes}} </span>
        <div class="btn-group">
           <button class="btn btn-default"> I Like this </button>
           <button class="btn btn-default"> I hate this </button>
        </div>
    </div>
</div>

BackBone Script of Model View:

var newsMV = Backbone.View.extend({
            tagName     :   "div",
            className   :   "news",
            initialize  :   function(){
                  this.listenTo(this.model, 'change', this.render);
            },
            events: {
                "click .btn-default" :   "clicked"
            },
            template    :   Handlebars.compile($('#item-template').html()),
                clicked: function(e){
                e.preventDefault();
                // Incrementing like or dislike attribute based on button 
                // Setting the attribute in Model to trigger a change event
            },
            render: function(){
              var output  =   this.template({'ModelItem':this.model.toJSON()});
              this.$el.html(output);
              return this;
            }  
});            

Now, as evident from the names, Clicking 'I Like this' button has to increment ModelItem.likes attribute and clicking 'I hate this' button has to increment the count of ModelItem.dislikes. Some of the things I tried was using an extra class name as identifier :

<button class="btn btn-default btn-like"> I Like this </button>
<button class="btn btn-default btn-dislike"> I hate this </button>

Now, within the clicked(), I can use simple jQuery something like :

clicked: function(e){
    e.preventDefault();
    if(e.currentTarget.hasClass('btn-like')){
        var like_count = this.model.get("likes");
        this.model.set({likes:++like_count});
    }
    else if(e.currentTarget.hasClass('btn-dislike')){
        var dislike_count = this.model.get("dislikes");
        this.model.set({dislikes:++dislike_count});
    }
 },

So this can set the appropriate model attibutes based on click, also another flexibility is the elimination of ID's for different news stories. With the same class name to multiple news items in the view, based on the click, I can access the clicked Model Button and perform the changes and re-render.

However, unlike Angular JS where DOM manipulation does not affect the binding of data and controller, here in this case, manipulating the class names or inter-changing the class names will directly affect the data in objects (and of course the changes are sent to server). Can this be prevented in Backbone?

I am a beginner in backbone and hence the googling for data-binding in backbone yielded results of epoxy and stickit. Both the options are using an ID to do data binding. I need to accomplish data-binding without ID's since ID's are unique.

Was it helpful?

Solution

I got an answer for my question in google groups. However wanted to share the answer here to help SO community of backbone users to get the right understanding:

Solution : Mickey's solution

Applying classes for identification:

<button class="btn btn-default js-likes"> I Like this </button>
<button class="btn btn-default js-dislike"> I hate this </button>

Observing the event of corresponding clicks:

events: {
         "click .js-likes": "updateLikesCounter",
         "click .js-dislike": "updateDislikesCounter",
         ...
},

Updating based on correponding button click:

updateLikesCounter: function() {
   this.model.set("likes", this.model.get("likes") + 1);
},
updateDisikesCounter: function() {
   this.model.set("dislikes", this.model.get("dislikes") + 1);
},

The important concept here was to understand that : These are different approaches (if angular and backbone are compared)- explicitly adding directives in the HTML vs. leaving the template clean of logic and attaching the handlers unobtrusively in the view object.

And that answers my question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top