简短版:我有一个Backbone模型,它有一个属性,第二个Backbone模型。第一个模型中的一个函数改变了第二个模型的状态,但是我的视图(正在监听第一个模型的更改)似乎没有获得第二个模型的状态,尽管任何数量的日志记录都表示否则(我一直在各个点记录this
以确认范围等)。我该如何解决这个问题?
长版本:我有一个代表学术课程的Backbone模型Course
和一个模型NameList
,它代表了一个Course
注册的学生列表{1}}。 Course
“有一个”NameList
。 NameList
由服务器上的单个文本文件支持。
我想在名为Course
的{{1}}模型中创建一个函数,该模型会创建一个新的importNameList
模型并导致NameList
模型转到NameList
它来自后端的数据。自我看来,fetch
正在倾听CourseView
模型的更改,而Course
模型有Course
,看起来这应该相应地更新视图。我的问题是它没有。
我想做什么
NameList
我必须做什么
var course = new Course();
var courseView = new CourseView({model : course});
courseView.model.importNameList('students.txt'); // Will cause view to re-render
这是我的日志记录代码。模型扩展var course = new Course(); // same
var courseView = new CourseView({model : course}); // same
courseView.model.importNameList('students.txt'); // same
courseView.render(); // Argh, manually calling this is ugly.
只是因为我认为它可以解决我的问题,但事实并非如此。
控制台输出
Backbone.DeepModel
Course.js
[console] var course = new Course();
[console] var courseView = new CourseView({model : course});
[console] course.importNameList('students.txt');
Course >>> importNameList
NameList >>> initialize()
NameList >>> fetch()
GET http://localhost/files/students.txt 200 OK 16ms
CourseView >>> render() // Render starts before fetch completes
CourseView <<< render() // Render finishes before fetch completes
Course <<< importNameList
NameList <<< fetch()
[console] courseView.render();
CourseView >>> render()
alice
bob
charlie
dan
erica
fred
george
CourseView <<< render()
NameList.js
var Course = Backbone.DeepModel.extend({
defaults : {
nameList : new NameList()
},
initialize: function(options) {
if (options && options.nameList) {
this.set({nameList : options.nameList});
}
},
importNameList : function(fileName) {
console.log("Course >>> importNameList");
var nameList = new NameList({fileName : fileName});
this.set({nameList : nameList});
console.log("Course <<< importNameList");
}
});
CourseView.js
var NameList = Backbone.DeepModel.extend({
defaults : {
fileName : 'new.txt',
names : []
},
initialize: function(options) {
console.log("NameList >>> initialize()");
var model = this;
if (options && options.fileName) {
model.set({fileName : options.fileName});
}
model.fetch();
},
fetch : function() {
console.log("NameList >>> fetch()");
var model = this;
$.ajax({
url : '/files/' + model.get('fileName'),
success : function(response) {
model.set({names : response.split('\n')});
console.log("NameList <<< fetch()");
}
});
}
});
答案 0 :(得分:0)
快速回答是使用jQuery deferred
对象。您可以在this article中找到有关使用backbone.js的延迟的更多信息。
我会添加更具体的信息,但我不清楚你为什么要重写fetch,这似乎是灾难的秘诀。我会坚持使用backbone的原始fetch方法并将其从NameList的初始化程序中删除,而不是从Course.js调用它,并使用从它返回的延迟来保证在获取完成后运行后面的步骤。
<强>更新强>
这是你可以做到这一点的一种方式的草图。首先从model.fetch();
的{{1}}方法中取出initialize
行,然后在NameList
中调用它,使用其返回值(延迟对象)作为返回值importNameList
:
importNameList
现在我们从var nameList = new NameList({fileName : fileName});
this.set({nameList : nameList});
return nameList.fetch()
返回延迟,我们可以使用它来保证在渲染之前完成提取:
importNameList
我认为应该做你想要的,虽然我还没有真正测试过它。
答案 1 :(得分:0)
我最终做了以下事情。
<强> CourseView.js:强>
// No changes.
在Course.js中:
importNameList : function(name) {
var model = this;
var nameList = new NameList({fileName : fileName});
// Set the attribute silently (without triggering a change event)
model.set({nameList : nameList}, {silent: true});
nameList.fetch({
success : function() {
model.change(); // Manually fire a change event when fetch completes.
}
});
}
在NameList.js中:
fetch : function(options) {
var model = this;
$.ajax({
url : '/files/' + model.get('fileName'),
success : function(response) {
model.set({lines : response.split('\n')});
// Make the "success" callback.
options.success();
}
});
}