Backbone: multiple View Models for the same model

Showing 1-13 of 13 messages
Backbone: multiple View Models for the same model Alper Sunar 12/22/11 10:06 AM
Can an experienced backbone coder chime in here?

http://stackoverflow.com/questions/8597726/backbone-multiple-view-models-for-the-same-model 
Re: Backbone: multiple View Models for the same model Alper Sunar 12/28/11 8:30 AM
Anybody?
Re: [backbonejs] Re: Backbone: multiple View Models for the same model Joshua Boyd 12/29/11 12:38 PM
On 12/28/2011 11:30 AM, Alper Sunar wrote:
> Anybody? --

The replies from a week ago look good to me.  What specifically is still
in question?

Re: [backbonejs] Re: Backbone: multiple View Models for the same model Alper Sunar 12/30/11 5:32 AM
The answer is suggesting that I extend the first view 
<ul>
<li><h3>Item 1 Name</h3>
<p>Item 1 Description</p>
<p>Tag1, Tag2 ,Tag3</p>
</li>
.......
</ul>
and provide a different template to render the second view
<ul>
<li>Tag1<span>{count of items tagged with tag1}</span></li>
<li>Tag2<span>{count of items tagged with tag2}</span></li>
<li>Tag3<span>{count of items tagged with tag3}</span></li>
</ul>
If both views are going to use the same model ex.  
{name: "Item1", description: "Item1 Desc", tags: ["Tag1", "Tag2", "Tag3"]}

Where should the code that will transform the above model to
 { tagName: "Tag1", tagCount: "3"}
go?

Is it second view's responsibility to iterate through each tag name and count the items that are tagged with that tag?

Thanks. 
 

Re: [backbonejs] Re: Backbone: multiple View Models for the same model Paul Yoder 12/30/11 6:28 AM
It's always better to have the model and/or collection perform any calculations. It keeps the view from having multiple responsibilities.

How is the tagCount being calculated?

I assume the model is part of a collection, and that tagCount is calculated from all the models in the collection.

If that is the case then I would suggest adding the following function to the collection:

getTagCount: function(tagName) {
  return this.filter(function(model) { return _.include(model.get('tags'), tagName); }).length;
}

And then you can add this function to your model:

tagCounts: function() {
  var tagCounts = [];
  _.each(this.get('tags'), function(tagName) {
    tagCounts.push({
      tagName: tagName,
      tagCount: this.getTagCount(tagName)
    });
  }, this);
  return tagCounts;
}

In your 2nd view you can call this.model.tagCounts() which will return the data the way you want it formatted.


--
The Unofficial Backbone.js Group

Re: [backbonejs] Re: Backbone: multiple View Models for the same model Alper Sunar 12/31/11 5:14 AM
Hi Paul,

Thanks for the info. Your assumptions are correct  the model is part of a collection, and tagCount is calculated from all the models in the collection.

However, when I add the following function my model I get Uncaught TypeError: Object [object Object] has no method 'getTagCount' error.
It makes sense, since I am adding the tagCounts function to my model. "this" refers to the model right? However, getTagCount function is added to the collection.

Am I missing something here?

Thanks.  
Re: [backbonejs] Re: Backbone: multiple View Models for the same model Alper Sunar 12/31/11 5:15 AM
Model and Collection

   window.Item = Backbone.Model.extend({
   // Default attributes for a todo item.

    tagCounts: function() {
        var tagCounts = [];
        _.each(this.get('tags'), function(tagName) {
            tagCounts.push({
                tagName: tagName,
                tagCount: this.getTagCount(tagName)
        });
  }, this);
  return tagCounts;
},

    defaults: function() {
      return {
        order: Items.nextOrder()
      };
    }
});



window.ItemList = Backbone.Collection.extend({

    // Reference to this collection's model.
    model: Item,

    // Save all of the todo items under the `"items"` namespace.
    localStorage: new Store("items"),


    getTagCount: function(tagName) {
         return this.filter(function(model) { return _.include(model.get('tags'), tagName); }).length;
    },


    // We keep the Items in sequential order, despite being saved by unordered
    // GUID in the database. This generates the next order number for new items.
    nextOrder: function() {
      if (!this.length) return 1;
      return this.last().get('order') + 1;
    },

    comparator: function(item) {
      return item.get('order');
    }

});
Re: [backbonejs] Re: Backbone: multiple View Models for the same model Paul Yoder 12/31/11 5:24 AM
Good catch. That was a mistake on my part. Since I only wrote the code in the email and didn't test it, I did not catch my mistake.

It should be tagCount: this.collection.getTagCount(tagName) in the tagCounts function on the model.
 

--
The Unofficial Backbone.js Group

Re: [backbonejs] Re: Backbone: multiple View Models for the same model Alper Sunar 1/1/12 2:18 AM

tagCounts: function() {
  var tagCounts = [];
  _.each(this.get('tags'), function(tagName) {
    tagCounts.push({
      tagName: tagName,
      tagCount: this.collection.getTagCount(tagName)
    });
  }, this);
  return tagCounts;
}
 
I have a few questions about the model code. Say we have the following list of items

{name: "Item 1", description: "Item 1 description", tags: ["Tag 1"] }
{name: "Item 2", description: "Item 2 description", tags: ["Tag 1", "Tag 2"] }
{name: "Item 3", description: "Item 3 description", tags: ["Tag 3"] }

Following is the transformed view model I would like to display.
{tagName: "Tag 1",  tagCount : 2 }
{tagName: "Tag 2",  tagCount : 1 } 
{tagName: "Tag 3",  tagCount : 1 }


If we add tagCounts function to the model (in this case the item class). Every item in the list will have a tagCounts function correct?

If we call tagCounts function on the first item in the list, it will return:
{tagName: "Tag 1",  tagCount : 2 }  ==> First item is tagged with Tag 1 only, therefore it will ask the collection to count the items that are tagged with Tag 1

If we call tagCounts function on the second item in the list, it will return:
{tagName: "Tag 1",  tagCount : 2 }  ==> Second item is tagged with Tag 1 and Tag 2 only, therefore it will ask the collection to count the items that are tagged with Tag 1 and Tag 2
{tagName: "Tag 2",  tagCount : 1 } 

If we call tagCounts function on the third item in the list, it will return:
{tagName: "Tag 3",  tagCount : 1 }  ==> Thrid item is tagged with Tag 3 only, therefore it will ask the collection to count the items that are tagged with Tag 3


None of the results returned by the tagCounts function will match the view model. I would like to display.

Can you elaborate on how I can get the count for all tags in the item list?









Re: [backbonejs] Re: Backbone: multiple View Models for the same model Paul Yoder 1/1/12 10:56 AM
If we add tagCounts function to the model (in this case the item class). Every item in the list will have a tagCounts function correct?

Yes, every model will have access to the tagCounts function.

You are also correct in your explanation of how tagCounts will work.

I assumed your 2nd view model wanted the tag counts for only the tags of that specific model. (e.g. if the model only has the 'Tag 1' tag, it will only show the tag count for 'Tag 1'. 

If you want the tag count for all the tags to be displayed in the 2nd view, then you will not need the tagCount function on the model, and you can update the getTagCount on the collection to return the tag count for all the tags. Here is how you can update getTagCount on the collection

getTagCount: function() {
  var tagCounts = [];
  var tagNames = _.unique(_flatten(this.pluck('tags')));
  _.each(tagNames, function(tagName) {
    var count = this.filter(function(model) { return _.include(model.get('tags'), tagName); 
    tagCounts.push({
      tagName: tagName,
      tagCount: count
    });
  , this);
  return tagCounts;
}

I believe that function will return the data type you are looking for.

--
The Unofficial Backbone.js Group

Re: [backbonejs] Re: Backbone: multiple View Models for the same model Alper Sunar 1/4/12 6:40 AM
Thanks Paul. I will use this function and report back the results
Re: [backbonejs] Re: Backbone: multiple View Models for the same model Alper Sunar 1/4/12 1:29 PM
Works great! Thanks a lot Paul.
Re: [backbonejs] Re: Backbone: multiple View Models for the same model Amy Schultz 8/20/13 4:25 PM
It seems like Underscore's countBy method could also have been used to help simplify this solution.

countBy_.countBy(list, iterator, [context]) 
Sorts a list into groups and returns a count for the number of objects in each group. Similar to groupBy, but instead of returning a list of values, returns a count for the number of values in that group.

_.countBy([1, 2, 3, 4, 5], function(num) {
  return num % 2 == 0 ? 'even' : 'odd';
});
=> {odd: 3, even: 2}

On Wednesday, January 4, 2012 1:29:27 PM UTC-8, Alper Sunar wrote:
Works great! Thanks a lot Paul.