我有一个简单的FullName
viewcomponent,里面有knockout viewmodel:
p>First name: <strong data-bind="text: firstName"></strong></p>
<p>Last name: <strong data-bind="text: lastName"></strong></p>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<p>Full name: <strong data-bind="text: fullName"></strong></p>
<script>
function AppViewModel() {
this.firstName = ko.observable("");
this.lastName = ko.observable("");
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
}
ko.applyBindings(new AppViewModel());
</script>
当我调用此组件时,如@(await Component.InvokeAsync("FullName"))
,它运行良好。
但是,当我尝试多次调用此组件时:
@(await Component.InvokeAsync("FullName"))
@(await Component.InvokeAsync("FullName"))
@(await Component.InvokeAsync("FullName"))
//etc...
我有一个错误,Knockout无法应用多个相同的绑定。
那么,如何将具有Knockout视图模型的多个ViewComponent包含在一个页面中?
答案 0 :(得分:2)
在你的代码中,你为每个添加的组件调用MiniTest::Spec
一次,并且Knockout不会让你多次绑定一些东西,除非你先删除绑定(根据Matt.kaaj的评论)。
话虽如此,如果您想在多个地方重复使用您的viewmodel,我认为您应该查看scoping your bindings。
完全披露 - 我对asp.net及其ViewComponents 了解不多,所以如果语法不正确,请道歉,但似乎他们支持passing in parameters。看起来您可以通过将组件定义更改为以下内容来解决此问题:
applyBindings
然后用:
初始化<div id=${idThatIPassIn}>
<p>First name: <strong data-bind="text: firstName"></strong></p>
<p>Last name: <strong data-bind="text: lastName"></strong></p>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<p>Full name: <strong data-bind="text: fullName"></strong></p>
</div>
<script>
function AppViewModel() {
this.firstName = ko.observable("");
this.lastName = ko.observable("");
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this);
}
ko.applyBindings(new AppViewModel(), document.getElementById('${idThatIPassIn}'));
</script>
这样,每次你告诉knockout应用绑定时,绑定被上下文化为包含你的@(await Component.InvokeAsync("FullName"), new { idThatIPassIn = "name-1" })
@(await Component.InvokeAsync("FullName"), new { idThatIPassIn = "name-2" })
@(await Component.InvokeAsync("FullName"), new { idThatIPassIn = "name-3" })
元素的单个div,所以你最终不会试图重新绑定已经存在的东西受到约束。
或者,您可以分配随机任意ID并绑定到该ID,而不是传入ID。在任何一种情况下,都可以将applyBindings调用范围限定为元素。
编辑 - 您提到不想按ID绑定。而是尝试使用类和jQuery's .each方法。类似的东西:
<p>
按照您目前的规定进行初始化:
<div class="name-block">
<p>First name: <strong data-bind="text: firstName"></strong></p>
<p>Last name: <strong data-bind="text: lastName"></strong></p>
<p>First name: <input data-bind="value: firstName" /></p>
<p>Last name: <input data-bind="value: lastName" /></p>
<p>Full name: <strong data-bind="text: fullName"></strong></p>
</div>
然后在另一个单独的 .js include中,添加:
@(await Component.InvokeAsync("FullName"))
@(await Component.InvokeAsync("FullName"))
@(await Component.InvokeAsync("FullName"))
这样,您的viewmodel只定义一次,并且您的绑定将应用于具有类&#34; name-block&#34;的每个div。
我还将整个过程包装在jQuery的document ready函数中,因此您可以安全地假设DOM已准备好进行操作。只需确保您的脚本也包含在您的页面中,因为它现在已与视图组件分开。