BackboneJS-监听嵌套的模型更改
BackboneJS - listening to nested model changes
简短版本:我有一个骨干模型,它的属性之一是第二个骨干模型。第一个模型中的一个函数会更改第二个模型的状态,但我的视图,即监听第一个模型的更改,似乎并没有获取第二个模式的状态,尽管有大量的日志记录表明情况并非如此(我一直在不同的点记录this
以确认范围等)。我该如何解决这个问题?
长版本:我有一个代表学术课程的主干模型Course
和一个代表Course
注册学生列表的模型NameList
。一个Course
"有一个"NameList
。NameList
由服务器上的单个文本文件支持。
我想在Course
模型中有一个名为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
只是因为我认为它可以解决我的问题,但它没有。
控制台输出
[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()
Course.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");
}
});
NameList.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()");
}
});
}
});
CourseView.js
var CourseView = Backbone.View.extend({
initialize : function(options) {
var view = this;
if (options && options.model) {
view.model = options.model;
} else {
view.model = new Course();
}
view.model.on('change', function() {
view.render();
});
},
render : function() {
console.log("CourseView >>> render()");
var names = this.model.get('nameList').get('names');
for (var i = 0; i < names.length; i++) {
console.log(names[i]);
}
console.log("CourseView <<< render()");
return this;
}
});
快速答案是使用jQuery一个deferred
对象。您可以在本文中找到更多关于在backbone.js中使用defereds的信息。
我想添加更多具体的信息,但我不太清楚你为什么要覆盖fetch,这似乎是一场灾难。我会坚持使用主干的原始fetch方法,并将其排除在NameList的初始值设定项之外,而是从Course.js中调用它,并使用它返回的延迟值来确保在fetch完成后运行后面的步骤。
更新:
这是一个可以做到这一点的方法的草图。首先从NameList
的initialize
方法中取出model.fetch();
行,并在importNameList
中调用它,使用它的返回值(一个延迟对象)作为importNameList
:的返回值
var nameList = new NameList({fileName : fileName});
this.set({nameList : nameList});
return nameList.fetch()
现在我们从importNameList
返回一个延迟的,我们可以使用它来保证在渲染之前完成提取:
this.deferred = courseView.model.importNameList('students.txt');
this.deferred.done(function() { courseView.render() });
我认为这应该是你想要的,尽管我还没有真正测试过。
我最终完成了以下操作。
CourseView.js:
// No changes.
课程内部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();
}
});
}
- 如何在AngularJS中监听点击事件,而不是触摸事件
- BackboneJS-监听嵌套的模型更改
- 在Firefox restartless插件中,当一个新窗口打开时,我如何运行代码(监听窗口打开)
- 监听touchend有时会触发移动点击事件
- 使用ajax的Django jquery.如何让jquery监听id's生成的表单
- JQuery监听点击并使用点击元素发出警报's href
- jQuery有没有,或者有没有jQuery插件,内置了监听CSS3动画事件的功能(例如animationEnd)
- 如何让Google Maps API v3监听dragend事件并在投递时填充表单字段
- 如何在angular js中监听dom就绪事件
- Phonegap:监听页面并关闭InAppBrowser返回index.html的简单方法
- React鼠标事件在没有监听它们的组件上触发
- 监听发布到网站的广告的新网址
- 我应该使用什么模式在 Node/JavaScript 中制作监听机器人
- 如何在具体化 CSS 中监听<选择>更改事件
- 如何将誓言令牌推送到本地存储或本地会话并监听存储事件?(SoundCloud Php/JS 错误解决方法)
- 在 nsiWindowWatcher 或 nsiWindowMediator 上监听焦点/模糊?对于火狐扩展
- 一个“;监听路由器”;(响应视图/模型中的路由器事件)
- js collection不监听模型更改事件
- 如何在骨干js中从你的模型中监听其他模型事件
- 主干监听嵌套模型/集合