BackboneJS is the best way to reorder models in a collection while maintaining a 0-indexed ordinal property for each model

I have a problem I'm playing with here, I have a collection of BackboneJS models, each model has a โ€œordinalโ€ property that tracks its order in the collection.

Here are my game data

var ex_group_test_data = [{ title: 'PRE EXERCISE', id: 0, ordinal: 1, group_items: [{ id: 0, ordinal: 0, title: 'item 1' },{ id: 1, ordinal: 1, title: 'item 2' }] },{ title: 'MAIN PART', id: 1, ordinal: 0, group_items: [{ id: 2, ordinal: 0, title: 'item 3', description: 'testing descrip' },{ id: 3, ordinal: 1, title: 'item 4' }] },{ title: 'POST EXERCISE BS', id: 2, ordinal: 2, group_items: [{ id: 2, ordinal: 0, title: 'item 5', description: 'testing descrip' },{ id: 3, ordinal: 1, title: 'item 6' }] }]; 

And here is the gist of my core network

  Collections.Exercise_Groups = Backbone.Collection.extend({ model: Models.Exercise_Group, comparator: function(model){ return model.get('ordinal'); }, initialize: function(){ return this; } 

The launch is simple, I want to be able to take the model and transfer its +1 or -1 serial number and support 0-indexing of all models in the collection.

In the end, I want to bring this to the level where I can fall into models or remove them from any position and still maintain my 0-indexing, or take the model and move it +/- X positions.

Does anyone have recommended ways to accomplish this?

EDIT 1

I developed a solution, maybe I want to optimize it tomorrow after I really get some sleep. It supports 0-indexing the โ€œordinals" of my models in my collection, regardless of whether I move the model forward or backward relative to its original position.

EDIT 2 Err actually has errors in fringes.

 /** * Move model to a specified location. * * @param int [model id] * @param int [mew item position] * @return this */ move_to: function(m_id, new_pos){ //keep within range if(new_pos < 0) new_pos = 0; else if(new_pos > (this.length - 1)) new_pos = this.length - 1; var model = this.get(m_id), old_pos = model.get('ordinal'); model.set({ ordinal: new_pos }); if(new_pos == old_pos){ //trigger associated events this.sort(); return this; } //update indexes of affected models this.each(function(m){ //ordinal of current model in loop var m_ordinal = m.get('ordinal'); //skip if this is the model we just updated if(m.get('id') == m_id) return; if(old_pos < new_pos){ //moving down, ordinal is increasing if(m_ordinal <= new_pos && m_ordinal != 0){ //this is in the range we care about m.set({ ordinal: m.get('ordinal') - 1 }); } }else if(old_pos > new_pos){ //moving up, ordinal is decreasing if(m_ordinal >= new_pos && (m_ordinal != (this.length - 1))){ //this is in the range we care about m.set({ ordinal: m.get('ordinal') + 1 }); } } }); this.sort(); return this; } 

EDIT 3 Well, I think I fixed all the problems, some simple things. Here is some code that I tested quite carefully, and I believe that it works.

 /** * Move model to a specified location. * * @param int [model id] * @param int [mew item position] * @return this */ move_to: function(m_id, new_pos){ //keep within range if(new_pos < 0) new_pos = 0; else if(new_pos > (this.length - 1)) new_pos = this.length - 1; var model = this.get(m_id), old_pos = model.get('ordinal'); log('old_pos ' + old_pos); log('new_pos ' + new_pos); model.set({ ordinal: new_pos }); if(old_pos == new_pos){ //trigger associated events this.sort(); return this; } var _this = this; //update indexes of affected models this.each(function(m){ //ordinal of current model in loop var m_ordinal = m.get('ordinal'); //skip if this is the model we just updated if(m.get('id') == m_id) return; if(old_pos < new_pos){ //moving down, ordinal is increasing if(m_ordinal <= new_pos && !(m_ordinal <= 0)){ //this is in the range we care about m.set({ ordinal: m.get('ordinal') - 1 }); } }else if(old_pos > new_pos){ //moving up, ordinal is decreasing log('p1'); if(m_ordinal >= new_pos && !(m_ordinal >= (_this.length - 1))){ //this is in the range we care about m.set({ ordinal: m.get('ordinal') + 1 }); } } }); this.sort(); return this; } 

EDIT 4

Found another mistake, fixed it.

 Backbone.Collection.prototype.move_to = function(m_id, new_pos) { //keep within range if(new_pos < 0) new_pos = 0; else if(new_pos > (this.length - 1)) new_pos = this.length - 1; var model = this.get(m_id), old_pos = model.get('ordinal'); log('old_pos ' + old_pos); log('new_pos ' + new_pos); model.set({ ordinal: new_pos }); if(old_pos == new_pos){ //trigger associated events this.sort(); return this; } var _this = this; //update indexes of affected models this.each(function(m){ log(m.id); //ordinal of current model in loop var m_ordinal = m.get('ordinal'); //skip if this is the model we just updated if(m.get('id') == m_id) return; if(old_pos < new_pos){ //moving down, ordinal is increasing if(m_ordinal <= new_pos && m_ordinal >= old_pos && !(m_ordinal <= 0)){ //this is in the range we care about m.set({ ordinal: m.get('ordinal') - 1 }, { silent: true }); } }else if(old_pos > new_pos){ //moving up, ordinal is decreasing log('p1'); if(m_ordinal >= new_pos && m_ordinal <= old_pos && !(m_ordinal >= (_this.length - 1))){ //this is in the range we care about m.set({ ordinal: m.get('ordinal') + 1 }, { silent: true }); } } }); this.sort(); return this; }; 
+4
javascript collections models
source share
1 answer

If you look at the source code of backbone.js, you will find that, for example, the add method supports adding models to specific indexes using

collectionName.add(model, {at: index});

Removing from a position may require you to create a custom function in the collection, for example:

 // Your Collection removeAt: function(options) { if (options.at) { this.remove(this.at(options.at)); } } 

for + 1 / -1 you can create a custom function and use the built-in index underscore function

 // Your Collection moveUp: function(model) { // I see move up as the -1 var index = this.indexOf(model); if (index > 0) { this.remove(model, {silent: true}); // silence this to stop excess event triggers this.add(model, {at: index-1}); } } moveDown: function(model) { // I see move up as the -1 var index = this.indexOf(model); if (index < this.models.length) { this.remove(model, {silent: true}); // silence this to stop excess event triggers this.add(model, {at: index+1}); } } 

That way you can also implement moveUp and moveDown for the models themselves for more readable code!

 // Your Model moveUp: function() { this.collection.moveUp(this); } // And the same for moveDown 

But now the index property is not saved in the models themselves. To read the index, simply use collection.indexOf(model) , but if you want to permanently store this information in models, you can bind to the add and remove events to update all indexes when making changes to the collection:

 // Your collection initialize: function(options?) { ... this.on('add remove', this.updateModelOrdinals); ... }, ... updateModelOrdinals: function() { this.each(function(model, index) { this.model.set('ordinal', index); }); } 

et voilร ! Now you should have the necessary functionality without reinventing the wheel while maintaining 0-indexing using your own Backbone functions! Sorry for leaving a bit, ask if I missed your head. And read the source backbone.js , you can find here seriously useful material!

Hope this helps!

+23
source share

All Articles