我有一个问题我在这里玩,我有一个BackboneJS模型的集合,每个模型都有一个'序数'属性,跟踪它在集合中的顺序。
这是我的播放数据
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'
}]
}];
以下是我的骨干系列的要点
Collections.Exercise_Groups = Backbone.Collection.extend({
model: Models.Exercise_Group,
comparator: function(model){
return model.get('ordinal');
},
initialize: function(){
return this;
}
从简单开始,我希望能够获取模型并将其移动+1或-1序数并保持集合中所有模型的0索引。
最终我想把它带到一个水平,我可以放入模型或从任何位置移除它们并仍然保持我的0索引,或者采取模型并将其移动+/- X位置。
任何人都有推荐的方法来实现这个目标吗?
编辑1
我已经找到了一个解决方案,我可能希望在我真正睡了之后明天优化它。它维持我的模型中“模型”的“序数”的0索引,无论我是将模型相对于原始位置向前还是向后移动。
编辑2 实际上它在边缘情况下有错误。
/**
* 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;
}
编辑3 好吧,我想我已经修复了所有问题,一些简单的范围内容。这里有一些我已经彻底测试的代码,我相信它有效。
/**
* 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;
}
编辑4
找到另一个错误,修补它。
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;
};
答案 0 :(得分:23)
如果查看backbone.js源代码,您会发现例如add方法支持使用
向某些索引添加模型 collectionName.add(model, {at: index});
从位置移除可能需要您为集合创建自定义函数,例如:
// Your Collection
removeAt: function(options) {
if (options.at) {
this.remove(this.at(options.at));
}
}
对于+1 / -1,您可以创建自定义函数并使用内置下划线indexOf-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});
}
}
通过这种方式,您还可以将moveUp和moveDown实现为模型本身,以获得更易于阅读的代码!
// Your Model
moveUp: function() {
this.collection.moveUp(this);
}
// And the same for moveDown
但是现在索引属性没有保存在模型本身中。要读取索引,只需使用collection.indexOf(model)
,但如果要始终在模型中存储该信息,则可以绑定到add
和remove
事件以在更改时更新所有索引收集到:
// Your collection
initialize: function(options?) {
...
this.on('add remove', this.updateModelOrdinals);
...
},
...
updateModelOrdinals: function() {
this.each(function(model, index) {
this.model.set('ordinal', index);
});
}
etvoilà!现在你应该拥有你需要的功能而不需要重新发明轮子,并且仍然使用Backbone自己的功能保持0索引!抱歉有点被带走,问我是不是已经过了头。阅读the backbone.js source,你可以找到非常有用的东西!
希望这有帮助!