javascript 骨干收藏刷新所有项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9309893/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Backbone Collection refresh all items
提问by kernelpanic
I'm having problems refreshing collection or more precisely collection view after updating all models on the server. Here's my scenario:
更新服务器上的所有模型后,我在刷新集合或更精确的集合视图时遇到问题。这是我的场景:
I have a collection of questions fetched from the server. Each question has a position attribute so I can manipulate the order in the list and save it back to the server with appropriate order.
I have a view for each single list item and a view with a more global scope that generates each list items and updates the collection. Basically I was using an example from O'Reilly book "Javascript Web Applications" which resembles a lot to the famous Todo annotated tutorial found here: http://documentcloud.github.com/backbone/docs/todos.htmlSo the structure is almost identical apart from a few custom models. Everythings works fine.
However, I'm having problems updating the collection with I reorder items in the I've a method in my global view which fires evert time I drag list items in the list. Btw it works well and updates the order of the items on the server, but I also want to be able to update the digit in from of each item in the list.
window.QuestionView = Backbone.View.extend({ el: $("#content"), events : { 'sortupdate ol#questions': 'sortStuff' }, initialize: function(collection) { this.collection = new QuestionsList; _.bindAll(this, 'addOne', 'addAll', 'render', 'addNewItem', 'addItem'); this.collection.bind('add', this.addNewItem); this.collection.bind('all', this.render); this.collection.bind('reset', this.addAll); this.collection.fetch({ data: { quiz_id: $qid }, processData:true }); }, render: function() {}, sortStuff: function() { $this = this; $.ajax({ url: "/hq/reorder/", type: "POST", data: $("#questions").sortable("serialize")+"&id="+$qid, dataType: 'json', success: function(data) { } }); }, addItem: function() { this.collection.add({title: 'New title goes here'}); return false; }, addNewItem: function(question) { var view = new ItemView({model: question, parent: this}); var element = view.render().el; this.$("#questions").prepend(element); $that = this; $(view.render().el).addClass('new'); }, addOne: function(question) { var view = new ItemView({model: question, parent: this}); this.$("#questions").prepend(view.render().el); }, addAll: function() { this.collection.each(this.addOne); return false; }
});
我有一系列从服务器获取的问题。每个问题都有一个位置属性,因此我可以操纵列表中的顺序并以适当的顺序将其保存回服务器。
我有每个列表项的视图和一个具有更全局范围的视图,该视图生成每个列表项并更新集合。基本上,我使用的是 O'Reilly 书中的“Javascript Web Applications”中的一个示例,它与此处找到的著名的 Todo 注释教程非常相似:http://documentcloud.github.com/backbone/docs/todos.html所以除了一些自定义模型之外,结构几乎相同。一切正常。
但是,我在更新集合时遇到了问题,我在全局视图中有一个方法重新排序项目,该方法会在我拖动列表中的列表项目时触发。顺便说一句,它运行良好并更新服务器上项目的顺序,但我也希望能够更新列表中每个项目的数字。
window.QuestionView = Backbone.View.extend({ el: $("#content"), events : { 'sortupdate ol#questions': 'sortStuff' }, initialize: function(collection) { this.collection = new QuestionsList; _.bindAll(this, 'addOne', 'addAll', 'render', 'addNewItem', 'addItem'); this.collection.bind('add', this.addNewItem); this.collection.bind('all', this.render); this.collection.bind('reset', this.addAll); this.collection.fetch({ data: { quiz_id: $qid }, processData:true }); }, render: function() {}, sortStuff: function() { $this = this; $.ajax({ url: "/hq/reorder/", type: "POST", data: $("#questions").sortable("serialize")+"&id="+$qid, dataType: 'json', success: function(data) { } }); }, addItem: function() { this.collection.add({title: 'New title goes here'}); return false; }, addNewItem: function(question) { var view = new ItemView({model: question, parent: this}); var element = view.render().el; this.$("#questions").prepend(element); $that = this; $(view.render().el).addClass('new'); }, addOne: function(question) { var view = new ItemView({model: question, parent: this}); this.$("#questions").prepend(view.render().el); }, addAll: function() { this.collection.each(this.addOne); return false; }
});
Also my success: function(data) returns the new order as a list (or JSON object) from the server. maybe I can reuse this order to set each model with a new value without making unnecessary fetch() call on the server each time the order is changed?
我的成功也是:函数(数据)从服务器以列表(或 JSON 对象)的形式返回新订单。也许我可以重用这个订单来为每个模型设置一个新值,而无需在每次更改订单时在服务器上进行不必要的 fetch() 调用?
EDIT:
编辑:
I finally managed to get it to work with a reset, clearing the view and re-fetching a new collection. Perhaps it isn't the best way to do it since there's additional call to the server with a fetch()..
我终于设法让它通过重置工作,清除视图并重新获取新集合。也许这不是最好的方法,因为使用 fetch()..
sortStuff: function() {
$this = this;
$.ajax({
url: "/hq/reorder/",
type: "POST",
data: $("#questions").sortable("serialize")+"&id="+$qid,
dataType: 'json',
success: function(data) {
$this.rerender();
}
});
},
rerender: function() {
this.collection.fetch({
data: { quiz_id: $qid },
processData:true
});
$("#questions").html("");
this.collection.reset();
this.addAll();
},
回答by Daniele B
I think your approach should be in two separate steps: 1) On one hand you update the data on the server 2) On the other hand you update the collection client-side
我认为您的方法应该分为两个单独的步骤:1)一方面更新服务器上的数据 2)另一方面更新客户端的集合
So, you are Ok on step 1, you said it works.
所以,你在第 1 步没问题,你说它有效。
For step 2, you can take advantage of the event driven programming. The logic is this one:
对于第 2 步,您可以利用事件驱动编程。逻辑是这样的:
- YOU JUST ADD ONE ELEMENT TO THE COLLECTION (collection.add(model) fires an 'add' event).
- In the collection, you listen for the 'add' event. When you catch it, you sort your collection again (collection.sort fires a 'reset' event)
- In your view for the list (questionView in your case) you listen for the collection reset event, and once it is fired you re-render your view
- 您只需向集合中添加一个元素(collection.add(model) 触发“添加”事件)。
- 在集合中,您侦听 'add' 事件。当你捕捉到它时,你再次对你的收藏进行排序(collection.sort 触发一个 'reset' 事件)
- 在您的列表视图中(在您的情况下为 questionView),您会监听集合重置事件,一旦它被触发,您就会重新呈现您的视图
Example code:
示例代码:
1) QuestionView: addItem removed and addNewItem simplified (it must no render)
1) QuestionView: addItem 被移除,addNewItem 被简化(它不能渲染)
window.QuestionView = Backbone.View.extend({
el: $("#content"),
events : {
'sortupdate ol#questions': 'sortStuff'
},
initialize: function(collection) {
this.collection = new QuestionsList;
_.bindAll(this, 'addOne', 'addAll', 'addNewItem');
this.collection.bind('add', this.addNewItem);
this.collection.bind('reset', this.addAll);
this.collection.fetch({
data: { quiz_id: $qid },
processData:true
});
},
render: function() {},
sortStuff: function() {
$this = this;
$.ajax({
url: "/hq/reorder/",
type: "POST",
data: $("#questions").sortable("serialize")+"&id="+$qid,
dataType: 'json',
success: function(data) {
}
});
},
//METHOD addItem REMOVED!!!
addNewItem: function(question) {
this.collection.add({title: 'New title goes here'}); //***IT FIRES AN ADD EVENT
},
addOne: function(question) {
var view = new ItemView({model: question, parent: this});
this.$("#questions").prepend(view.render().el);
},
addAll: function() {
this.collection.each(this.addOne);
return false;
}
});
});
2) the collection catch the add event and sorts (trigger 'reset' event)you can handle it always in the QuestionView, your initialize function becomes.
2)集合捕获添加事件并排序(触发“重置”事件),您可以始终在 QuestionView 中处理它,您的初始化函数变为。
initialize: function(collection) {
this.collection = new QuestionsList;
_.bindAll(this, 'addOne', 'addAll', 'addNewItem');
this.collection.bind('add', this.addNewItem);
this.collection.bind('reset', this.addAll);
this.collection.fetch({
data: { quiz_id: $qid },
processData:true
});
//ADD THIS*****
this.collection.on('add', function(){
this.collection.sort();
});
},
3) the third step is already done, you just re-render the view
3)第三步已经完成,你只需重新渲染视图
The best would be that you sort elements in your collection defining a new 'comparator' function, which uses the 'position' attribute of your list
最好的方法是对集合中的元素进行排序,定义一个新的“比较器”函数,该函数使用列表的“位置”属性
something like (in QuestionView)
类似(在 QuestionView 中)
this.collection.comparator: function(){
return this.collection.get("position");
}
so that items get ordered by position CLIENT SIDE
以便按位置CLIENT SIDE订购商品
**EDIT**Initialize function modified. Fetch is used instead of 'sort', which is unuseful as long as the 'position' attribute of each element in the collection is not updated.
**编辑* *初始化函数已修改。使用 Fetch 而不是 'sort',只要集合中每个元素的 'position' 属性没有更新,它就没有用。
initialize: function(collection) {
this.collection = new QuestionsList;
_.bindAll(this, 'addOne', 'addAll', 'addNewItem');
this.collection.bind('add', this.addNewItem);
this.collection.bind('reset', this.addAll);
this.collection.fetch({
data: { quiz_id: $qid },
processData:true
});
//ADD THIS*****
this.collection.on('add', function(){
this.collection.fetch();
});
回答by Nemanja Miljkovi?
You should do Questions.reset(data);
, however you need to tell ajax that the response is json:
您应该这样做Questions.reset(data);
,但是您需要告诉 ajax 响应是 json:
sortStuff: function() {
$.ajax({
url: '/order',
data: $("ol#questions").sortable('serialize'),
dataType: 'json',
success: function(data) {
// now data is an object
Questions.reset(data);
});
});
}
I hope you have learned that backbone is event driven, and that you have an event for collection reset bound to the render method, so there's no need to explicitly call render here.
我希望你已经了解到主干是事件驱动的,并且你有一个绑定到渲染方法的集合重置事件,所以没有必要在这里显式调用渲染。
EDIT:
编辑:
Ok, now with the code I see what you're trying to accomplish, and your logic is flawed. You shouldn't wait for the ajax call to return the new order. It's better if you update the order on the client side, and then save the model.
好的,现在通过代码,我看到了您要完成的任务,并且您的逻辑有缺陷。您不应等待 ajax 调用返回新订单。最好在客户端更新订单,然后保存模型。
Here's a jsfiddle sample: http://jsfiddle.net/b75px/
这是一个 jsfiddle 示例:http: //jsfiddle.net/b75px/
Combine that with backbone, and you should have:
将它与主干结合起来,你应该有:
Notethat I'm just guessing how you have organized the questions. If you have any other problems, update your question with more details.
请注意,我只是在猜测您是如何组织问题的。如果您有任何其他问题,请使用更多详细信息更新您的问题。
events: {
'sortstart ol#questions': 'startSortingQuestions',
'sortupdate ol#questions': 'updateQuestions'
},
startSortingQuestions: function(event, ui) {
this.beforeIndex = ui.item.index();
},
updateQuestions: function(event, ui) {
var before = this.beforeIndex,
after = ui.item.index();
// now that you have the index change, all you have to do is set the new index
// and save them to the database
this.collection.at(before).set({ index: after; }).save();
this.collection.at(after).set({ index: before; }).save();
// passing silent: true because sort invokes the reset event,
// and we don't need to redraw anything
this.collection.sort({ silent: true });
/* or maybe an even better approach:
var beforeModel = this.collection.at(before);
var toSwapModel = this.collection.at(after);
this.collection.remove(beforeModel);
this.collection.remove(toSwapModel);
this.collection.add(beforeModel, { at: after, silent: true });
this.collection.add(toSwapModel, { at: before, silent: true });
note that I have no idea on how your database is structured, so my guess is
every question has it's index so you know it's order
therefore, you should still update the model's index field or whatever it is you're doing
*/
}