【问题标题】:JsViews how to make data binding happen on root object as well as its nested properties?JsViews如何在根对象及其嵌套属性上进行数据绑定?
【发布时间】:2015-05-19 07:38:39
【问题描述】:

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

基本上,我有一个创建新公司并更新它们的表单。实际的创建/更新是通过 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);
}

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

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

【问题讨论】:

    标签: javascript jsviews


    【解决方案1】:

    您遇到的问题是因为在您的场景中,您有像 Company.Name 这样的路径,您希望将数据链接到不仅叶子属性的更改,而且还涉及涉及替换路径中较高对象的更改(在这种情况下公司)。

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

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

    另请参阅本主题中的示例,例如 Example: 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>
    

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

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

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

    以下是一些相关链接:

    【讨论】:

    • 非常感谢您分享指向相应部分的链接!具有讽刺意味的是,我过去曾经历过这两个部分,但是当我编写这段代码时,我并没有想到这是我必须做的。一个小问题:我应该使用任何其他构造来指示使用模板 X 而不是 for 渲染对象?
    【解决方案2】:

    我发现了一种方法来实现这一点。起初它可能看起来很复杂,但一旦你正确理解它就会有意义。

    (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,因此,如果有人遇到此问题并想了解此解决方案如何解决他们的特定问题,他们将能够使用有效的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-11
      • 1970-01-01
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多