Javascript Knockout.js多个外部模板&;多个虚拟机切换失败
我正在使用以下命令:Javascript Knockout.js多个外部模板&;多个虚拟机切换失败,javascript,templates,mvvm,knockout.js,Javascript,Templates,Mvvm,Knockout.js,我正在使用以下命令: 淘汰赛-2.1.0.js 我正在努力实现以下目标: 模板容器加载外部HTML并加载该HTML的特定VM(工作) 模板容器加载/切换到另一个外部HTML,以及该HTML的其他特定VM(工作) 模板容器切换回第一个模板/VM以及它们的VM(不工作!) 我猜它不起作用的原因是,模板是在VM之前加载的(它确实会给我绑定错误) 我的网站结构如下(不包括上述图书馆): index.html(保存模板容器) js/script.js(保存主视图模型) js/firstvm.j
- 淘汰赛-2.1.0.js
- 模板容器加载外部HTML并加载该HTML的特定VM(工作)
- 模板容器加载/切换到另一个外部HTML,以及该HTML的其他特定VM(工作)
- 模板容器切换回第一个模板/VM以及它们的VM(不工作!)
(保存模板容器)index.html
(保存主视图模型)js/script.js
(保存第一个视图模型)js/firstvm.js
(保存第二个视图模型)js/secondvm.js
(第一个VM的模板)tmpl/firstvm.html
(第二个VM的模板)tmpl/secondvm.html
- index.html
<button data-bind="click: loadFirstPage">Load first page + ViewModel</button> <button data-bind="click: loadSecondPage">Load second page + ViewModel</button> < hr /> <div data-bind="template: { name: function() { return currentTemplate(); }, data: currentData }"></div>
- firstvm.html
<p data-bind="text: displayValue"></p>
- secondvm.js
function SecondViewModel() { this.displayValue2 = ko.observable("Text from secondvm.js"); };
注:忘记提及:当两次按下“首页”按钮时,它似乎确实起作用(可能是因为加载了正确的虚拟机)。因此,问题似乎是名称和数据需要同时更改,这样模板就不会绑定到尚未存在的viewmodel。有几种方法可以解决这个问题。一种方法是加载模板并保留它们,但您可以继续这样重新加载它们: 模板绑定:
<div data-bind="template: {name: currentTemplate().name(),
data: currentTemplate().data() }"></div>
我测试了这个,它是有效的。您可能想对其进行更多的调整,但您已经明白了。这已经得到了回答,但是我想与大家分享我的解决方案,该解决方案用于标准的淘汰模板。我创建了自定义绑定,并将模板渲染调用包装到
setTimeout
中,以将渲染放在队列的末尾,效果很好。代码如下:
ko.bindingHandlers.widget = {
'init': function(element, valueAccessor) {
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var templateName = valueAccessor().widgetTemplate();
var dataValue = valueAccessor()
var innerBindingContext = bindingContext['createChildContext'](dataValue);
// This puts rendering of template to end of queue.
// This is to avoid binding errors while new template is assigned to old widget data
setTimeout(function(){
ko.renderTemplate(templateName, innerBindingContext, {}, element);
}, 0);
}
}
注意:自从模板绑定的
名称
以来您是否尝试将模板:{name:}绑定更改为直接绑定到计算的或可观察的而不是函数?在这种情况下,ko应该自动评估更改。@Nick Yup。不幸的是,这不起作用。data bind=“template:{name:currentmplate,data:currentData}”
对我有效。是的,这就是诀窍!问题确实是模板和数据需要同时更改,但我没有想到这个解决方案。这么简单,但有效-谢谢!绝妙的解决方案!请注意,您不需要额外的TemplateViewModel()函数。只需使用:vm.currentTemplate({name:'firstvm',data:new FirstViewModel()}),就可以使它变得简单一点代码>。
function SecondViewModel() {
this.displayValue2 = ko.observable("Text from secondvm.js");
};
<div data-bind="template: {name: currentTemplate().name(),
data: currentTemplate().data() }"></div>
function TemplateViewModel(name, data) {
this.name = ko.observable(name);
this.data = ko.observable(data);
};
function IndexViewModel() {
var vm = this;
this.currentTemplate = ko.observable();
this.loadFirstPage = function() {
vm.currentTemplate(new TemplateViewModel("firstvm", new FirstViewModel()));
};
this.loadSecondPage = function() {
vm.currentTemplate(new TemplateViewModel("secondvm", new SecondViewModel()));
};
this.loadFirstPage();
};
ko.applyBindings(new IndexViewModel());
ko.bindingHandlers.widget = {
'init': function(element, valueAccessor) {
return { 'controlsDescendantBindings': true };
},
'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var templateName = valueAccessor().widgetTemplate();
var dataValue = valueAccessor()
var innerBindingContext = bindingContext['createChildContext'](dataValue);
// This puts rendering of template to end of queue.
// This is to avoid binding errors while new template is assigned to old widget data
setTimeout(function(){
ko.renderTemplate(templateName, innerBindingContext, {}, element);
}, 0);
}
}