使用Asp.Net核心ViewComponents

时间:2016-10-07 15:22:10

标签: c# mvvm knockout.js asp.net-core

我有一个简单的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包含在一个页面中?

1 个答案:

答案 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已准备好进行操作。只需确保您的脚本也包含在您的页面中,因为它现在已与视图组件分开。