Insert an item into the backbone.js collection

Is there an easy way to insert a new model element in the middle of the backbone.js Collection and then update the View collection to include the new element in the correct position?

I am working on a control to add / remove items from a list. Each list item has its own Model and View , and I have a View for the entire collection.

Each element view has a Duplicate button, which clones the model of the element and inserts it into the collection at the index position below the element that was clicked.

Inserting an item into the collection was simple, but I find it difficult to figure out how to update the collection view. I tried something like this:

 ListView = Backbone.View.extend({ el: '#list-rows', initialize: function () { _.bindAll(this); this.collection = new Items(); this.collection.bind('add', this.addItem); this.render(); }, render: function () { this.collection.each(this.addItems); return this; }, addItem: function (item) { var itemView = new ItemView({ model: item }), rendered = itemView.render().el, index = this.collection.indexOf(item), rows = $('.item-row'); if (rows.length > 1) { $(rows[index - 1]).after(rendered); } else { this.$el.append(rendered); } } } 

This implementation seems to work, but I get weird errors when I add a new item. I'm sure I can sort them, but ...

There a voice in my head tells me that there is a better way to do this. You need to manually determine where to insert the new ItemView seems really hacked - shouldn't the collection view know how to re-collect?

Any suggestions?

+6
source share
2 answers

The usual way: let ListView display each ItemView in its render function. Then I just bind the add event to the render function, for example:

 ListView = Backbone.View.extend({ el: '#list-rows' , initialize: function () { _.bindAll(this); this.collection = new Items(); this.collection.bind('add', this.render); this.render(); } , render: function () { this.$el.empty(); var self = this; this.collection.each(function(item) { self.$el.append(new ItemView({ model: item }).render().el); }); return this; } } 

Each time you call this.collection.add(someModel, {at: index}) , the view will be redrawn accordingly.

+4
source

I don’t think that re-displaying the entire collection when adding a new item is the best solution. This is slower than inserting a new item in the right place, especially if the list is long.

Also consider the following scenario. You upload several items to your collections, and then add n more items (for example, the user clicks the "upload more" button). To do this, you call the fetch() method, passing add: true as one of the parameters. When data is received from the server, the add event will be fired n times, and you will finish re-rendering your list n times.

I really use the code option in your question, here is my answer to the add event:

 var view, prev, prev_index; view = new ItemView({ model: new_item }).render().el; prev_index = self.model.indexOf(new_item) - 1; prev = self.$el.find('li:eq(' + prev_index + ')'); if (prev.length > 0) { prev.after(view); } else { self.$el.prepend(view); } 

So, essentially, I just use a selector :eq() jQuery, instead of getting all the elements like you should use less memory.

+9
source

Source: https://habr.com/ru/post/910084/


All Articles