Backbone 子视图未正确呈现
Backbone subview not rendered properly
我开始使用 backbone.js 开发一个网站,在尝试了整个上午之后,我完全陷入了以下问题。
我这里只输出相关代码
我有一个名为 Navigator 的视图,其中包含一个记录集合(最初为空):
var NavigatorView = Backbone.View.extend({
template: JST['app/scripts/templates/Navigator.ejs'],
tagName: 'div',
id: '',
className: 'saiNavigator',
events: {},
initialize: function () {
this.currentRecords = new RecordsCollection();
this.currentRecords.on('reset', this.onRecordsCollectionReseted.bind(this));
},
onRecordsCollectionReseted: function(){
this.render();
},
render: function () {
var tplResult = this.template({
computeTemplate: this.computeTemplate,
records: this.currentRecords
});
this.$el.html(tplResult);
},
onDOMUpdated: function(){
var me = this;
var data = {
device : 'web',
gridId : this.model.get('gridId'),
filterId : this.model.get('filterId')
};
$.ajax({
url: App.getTokenedUrl() + '/task/getGridData.'+this.model.get('taskId')+'.action',
success: me.onRecordReceived.bind(me),
statusCode: {
500: App.handleInternalError
},
type: 'GET',
crossDomain: true,
data : data,
dataType: 'json'
});
},
onRecordReceived: function(result){
var newRecords = [];
for(var i = 0; i < result.items.length; i++){
var newRecord = new RecordModel(result.items[i]);
newRecords.push(newRecord);
}
this.currentRecords.reset(newRecords);
}
});
我有一个名为 dossier 的视图,html 是
<div id="dossier1" class="dossier">
<div id="dossier1-navContainer" class="navigatorContainer"/>
<div class="pagesNavigatorContainer"/>
<div class="pagesContainer"/>
<div class="readOnlyFiche"/>
</div>
当我第一次渲染档案时(我只渲染一次)我在下面的渲染函数中创建了导航器
render: function () {
this.$el.html(this.template({
uniqBaseId: this.id,
className: this.className
}));
var nav = this.navigator = new NavigatorView({
model : this.model,
id: this.id+'navigator',
el: $('#'+this.id+'-navContainer')
});
this.navigator.render();
//We notify the navigator that it's ready. This will allow the nav to load records
nav.onDOMUpdated();
}
}
如我们所见,我将“#dossier1-navContainer”id 提供给导航器,以便他在那里呈现
所以,这是它的工作原理。当我呈现档案时,它会创建一个导航器并将其插入 DOM。完成后,我通知导航器它可以通过 ajax 请求从服务器加载数据。当我收到答案时,我用传入的记录重置了数据集。
在导航器渲染函数中的 this.$el.html(tplResult) 之前,我输出结果字符串。
第一次
<div class="items"></div>
第二次拿到记录的时候是
<div class="items">
<div>item1</div>
<div>item2</div>
<div>item3</div>
</div>
所以模板生成是正确的。但是,当第二次渲染发生时,this.$el.html(tplResult) 会 NOTHING。如果我在浏览器中查看 DOM NOTHING CHANGED
但是,如果我将此行替换为
$('#dossier1-navigator').html(tplResult)
有效。这意味着第一次 $('#dossier1-navigator') 和 this.$el 是同一个对象,第二次不是。
我不知道为什么它在第二次使用标准 this.$el.
时不起作用
求助!!
提前致谢
编辑:在与 Seebiscuit 进行了大量讨论之后,我添加了有助于回答问题的几行内容
newTask.render();
var taskHtml = newTask.$el.html();
$('#mainTaskContainer').append(taskHtml);
我认为问题在于您没有使用传递给 navigatorView 的内容;
在你的 navigatorView 中试试这个:
initialize:function(el) {
this.$el=el
...
}
如果有帮助请告诉我
我的预感是您遇到了绑定问题。我建议你更换
this.currentRecords.on('reset', this.onRecordsCollectionReseted.bind(this)); },
在您的 initialize
中,其中:
this.listenTo(this.currentRecords, "reset", this.render);
无需特别绑定。 Backbone 的 listenTo
将回调出价给设置侦听器的 Backbone 对象(this.listenTo
中的 this
)。还有一个额外的好处,当您关闭视图(通过调用 this.remove()
)时,它会删除侦听器,并帮助您避免僵尸视图。
试试吧。
经过与 seebiscuit 无数分钟的讨论,我们得出了解决方案。问题全部出在 $el 元素的定义上。正式定义将其定义为
A cached jQuery object for the view's element. A handy reference instead of re-wrapping the DOM element all the time
从标准缓存的角度来看,这实际上不是很准确。从我的角度来看,至少缓存的原则是在没有值的情况下查找值,否则就使用它。然而,在这种情况下,情况并非如此。正如 Seebiscuit 告诉我的那样,
Because when you first bound this.$el = $(someelement) this.$el will always refer to the return of $(someelement) and not to $(someelement). When does the difference matter?
When the element is not in the DOM when you do the assignment
所以实际上,$el 持有选择器第一次查找的结果。因此,如果第一次查找未命中,那么它将永远不会成功!即使后面添加了元素。
我这里的错误是将主 dossierView 添加到 DOM after 渲染其 NavigatorView 子视图。如果 $el 是真正的缓存,我本可以找到解决方案,因为 ajax 回调中的第二次渲染会找到该元素。按照目前 $el 的工作方式,我一无所有。
结论:确保在您尝试呈现子视图时 DOM 正确呈现视图的每个部分。
我开始使用 backbone.js 开发一个网站,在尝试了整个上午之后,我完全陷入了以下问题。
我这里只输出相关代码
我有一个名为 Navigator 的视图,其中包含一个记录集合(最初为空):
var NavigatorView = Backbone.View.extend({
template: JST['app/scripts/templates/Navigator.ejs'],
tagName: 'div',
id: '',
className: 'saiNavigator',
events: {},
initialize: function () {
this.currentRecords = new RecordsCollection();
this.currentRecords.on('reset', this.onRecordsCollectionReseted.bind(this));
},
onRecordsCollectionReseted: function(){
this.render();
},
render: function () {
var tplResult = this.template({
computeTemplate: this.computeTemplate,
records: this.currentRecords
});
this.$el.html(tplResult);
},
onDOMUpdated: function(){
var me = this;
var data = {
device : 'web',
gridId : this.model.get('gridId'),
filterId : this.model.get('filterId')
};
$.ajax({
url: App.getTokenedUrl() + '/task/getGridData.'+this.model.get('taskId')+'.action',
success: me.onRecordReceived.bind(me),
statusCode: {
500: App.handleInternalError
},
type: 'GET',
crossDomain: true,
data : data,
dataType: 'json'
});
},
onRecordReceived: function(result){
var newRecords = [];
for(var i = 0; i < result.items.length; i++){
var newRecord = new RecordModel(result.items[i]);
newRecords.push(newRecord);
}
this.currentRecords.reset(newRecords);
}
});
我有一个名为 dossier 的视图,html 是
<div id="dossier1" class="dossier">
<div id="dossier1-navContainer" class="navigatorContainer"/>
<div class="pagesNavigatorContainer"/>
<div class="pagesContainer"/>
<div class="readOnlyFiche"/>
</div>
当我第一次渲染档案时(我只渲染一次)我在下面的渲染函数中创建了导航器
render: function () {
this.$el.html(this.template({
uniqBaseId: this.id,
className: this.className
}));
var nav = this.navigator = new NavigatorView({
model : this.model,
id: this.id+'navigator',
el: $('#'+this.id+'-navContainer')
});
this.navigator.render();
//We notify the navigator that it's ready. This will allow the nav to load records
nav.onDOMUpdated();
}
}
如我们所见,我将“#dossier1-navContainer”id 提供给导航器,以便他在那里呈现
所以,这是它的工作原理。当我呈现档案时,它会创建一个导航器并将其插入 DOM。完成后,我通知导航器它可以通过 ajax 请求从服务器加载数据。当我收到答案时,我用传入的记录重置了数据集。
在导航器渲染函数中的 this.$el.html(tplResult) 之前,我输出结果字符串。
第一次
<div class="items"></div>
第二次拿到记录的时候是
<div class="items">
<div>item1</div>
<div>item2</div>
<div>item3</div>
</div>
所以模板生成是正确的。但是,当第二次渲染发生时,this.$el.html(tplResult) 会 NOTHING。如果我在浏览器中查看 DOM NOTHING CHANGED
但是,如果我将此行替换为
$('#dossier1-navigator').html(tplResult)
有效。这意味着第一次 $('#dossier1-navigator') 和 this.$el 是同一个对象,第二次不是。
我不知道为什么它在第二次使用标准 this.$el.
时不起作用求助!!
提前致谢
编辑:在与 Seebiscuit 进行了大量讨论之后,我添加了有助于回答问题的几行内容
newTask.render();
var taskHtml = newTask.$el.html();
$('#mainTaskContainer').append(taskHtml);
我认为问题在于您没有使用传递给 navigatorView 的内容;
在你的 navigatorView 中试试这个:
initialize:function(el) {
this.$el=el
...
}
如果有帮助请告诉我
我的预感是您遇到了绑定问题。我建议你更换
this.currentRecords.on('reset', this.onRecordsCollectionReseted.bind(this)); },
在您的 initialize
中,其中:
this.listenTo(this.currentRecords, "reset", this.render);
无需特别绑定。 Backbone 的 listenTo
将回调出价给设置侦听器的 Backbone 对象(this.listenTo
中的 this
)。还有一个额外的好处,当您关闭视图(通过调用 this.remove()
)时,它会删除侦听器,并帮助您避免僵尸视图。
试试吧。
经过与 seebiscuit 无数分钟的讨论,我们得出了解决方案。问题全部出在 $el 元素的定义上。正式定义将其定义为
A cached jQuery object for the view's element. A handy reference instead of re-wrapping the DOM element all the time
从标准缓存的角度来看,这实际上不是很准确。从我的角度来看,至少缓存的原则是在没有值的情况下查找值,否则就使用它。然而,在这种情况下,情况并非如此。正如 Seebiscuit 告诉我的那样,
Because when you first bound this.$el = $(someelement) this.$el will always refer to the return of $(someelement) and not to $(someelement). When does the difference matter? When the element is not in the DOM when you do the assignment
所以实际上,$el 持有选择器第一次查找的结果。因此,如果第一次查找未命中,那么它将永远不会成功!即使后面添加了元素。
我这里的错误是将主 dossierView 添加到 DOM after 渲染其 NavigatorView 子视图。如果 $el 是真正的缓存,我本可以找到解决方案,因为 ajax 回调中的第二次渲染会找到该元素。按照目前 $el 的工作方式,我一无所有。
结论:确保在您尝试呈现子视图时 DOM 正确呈现视图的每个部分。