JsViews 如何使数据绑定发生在根对象及其嵌套属性上?

JsViews how to make data binding happen on root object as well as its nested properties?

当数据将一个对象链接到一个表单时,我遇到了奇怪的行为,这让我重新质疑数据绑定到底是什么?

基本上我有一个表单可以创建新公司并更新它们。实际的 creation/update 是通过 ajax 完成的,这就是为什么我为这两个目的使用相同的表格。在我必须创建公司的情况下,一切都按我的预期进行。但是,当我必须更新一家公司时,事情并不像我期望的那样运作。请看下面的代码。

这是我的示例表格 HTML:

<div id="result"></div>

<script type="text/x-jsrender" id="CompanyFormTemplate">
    <form>
        <input type="text" data-link="Company.Name" />
    </form>
</script>

这是我的 Javascript 代码:

var app = new CompanyFormContext();

function CompanyFormContext() { 
    this.Company = {
        Name: ''
    };

    this.setCompany = function (company) {
        if (company) {
            $.observable(this).setProperty('Company', company);
        }
    };
};

$(function () {
    initPage(); 

    ...

    if (...) {
        // we need to update company information

        app.setCompany({ Name: 'Company ABC' });
    }
});

function initPage() {
    var template = $.templates('#CompanyFormTemplate');
    template.link("#result", app);
}

表单输入显示 'Company ABC',它是空的。但是,如果我在其中输入任何内容,那么 Company.Name 值就会改变!但是,虽然我希望数据输入绑定到我的 Company 对象的 Name 属性,但我也希望它知道对(父)Company 对象所做的任何更改,并将其数据绑定更新到它的 Name 属性 相应地。

所以我的问题是我应该如何改变我编写这段代码的方式,以便我可以在根对象和 属性 上实现数据绑定?

我发现了一种实现此目的的方法。乍一看似乎很复杂,但一旦你正确理解它就会有意义。

(PS:我希望有这样的示例。我可能会写博客。)

HTML 标记:

<script type="text/x-jsrender" id="CompanyFormTemplate">
    <form>
        {^{for Company tmpl="#CompanyDetailsTemplate" /}
    </form>
</script>

<script type="text/x-jsrender" id="CompanyDetailsTemplate">
    <input type="text" data-link="Name" />
</script>

Javascript:无需对上述代码进行任何更改。


好吧,正如我所说,解决方案可能看起来很复杂,但事实证明我真正要做的就是首先在 Company 对象上设置数据绑定,然后再到它的 属性 对象。我想知道是否有更优雅的解决方案(即所有这些都可以在一个模板中实现)但是这个解决方案确保数据绑定发生在父对象及其属性上。

我已经为这个解决方案发布了 JsFiddle,所以如果有人遇到这个问题并想了解这个解决方案如何解决他们的特定问题,他们将能够使用一个有效的解决方案。

你遇到的问题是因为在你的场景中,你有像 Company.Name 这样的路径,你想要数据-link 不仅改变叶 属性 而且也涉及更换路径中更高级别的对象(在本例中为公司)的更改。

为此你需要使用语法 data-link="Company^Path".

请参阅本文档主题中的路径:叶更改或深度更改部分: http://www.jsviews.com/#observe@deep.

另请参阅本主题中的示例,例如 示例:JsViews with plain objects and arrayhttp://www.jsviews.com/#explore/objectsorvm.

这是您的 jsfiddle 的更新,使用的语法是:https://jsfiddle.net/msd5oov9/2/.

顺便说一句,FWIW,在你使用 {^{for}} 的修复中,你不必使用第二个模板——你也可以这样写:

<form class="form-horizontal">
    {^{for Company}}
        ...
        <input type="text" data-link="Name" />
    {{/for}}
</form>

要在下面的评论中也回答您的后续问题,您可以将任何 'block' 标签与模板相关联。在标签上使用 tmpl=... 意味着您已决定将块内容分离到一个单独的可重复使用的模板中。 (A 'partial',如果你愿意的话)。该模板的数据上下文将与块内的数据上下文相同。

具体来说,{{include}} {{if}} 和 {{else}} 标签不会移动数据上下文,但 {{for}} 和 {{props}} 会。使用自定义标签,您可以决定...

因此,在您的情况下,您可以使用 {^{for Company tmpl=.../}}{{include tmpl=.../}},但在第二种情况下,您引用的其他模板将使用 <input type="text" data-link="Company^Name" /> 而不是 <input type="text" data-link="Name" />

以下是一些相关的 link: