Knockout.js:绑定到复杂对象

时间:2012-11-18 09:39:50

标签: knockout.js

我是knockout.js的新手,我正在尝试绑定到代表用户的以下对象:

{
    "$id": "1",
    "$values": [
        {
            "$id": "2",
            "Locations": {
                "$id": "3",
                "$values": []
            },
            "Photos": {
                "$id": "4",
                "$values": []
            },
            "UserId": 1,
            "Name": "Test User"
        }
    ]
}

用户可以零个或多个位置,以及零个或多个照片。

视图模型:

function UsersViewModel() {
    var self = this;
    self.users = ko.observableArray();

    var baseUri = 'http://localhost:46241/api/users';

    $.getJSON(baseUri, function (data) {
        self.users = data;
    });
}

$(document).ready(function () {
    ko.applyBindings(new UsersViewModel());
})

HTML包含以下绑定:

<ul id="update-users" data-bind="foreach: users"> 
     <li> 
            <div><div class="item">User ID</div>
                <input type="text" data-bind="value: $data.UserId" />
            </div>                 
            <div><div class="item">Name</div>
                <input type="text" data-bind="value: $data.Name" />
            </div>                  
     </li> 
</ul>

我做错了吗?或者用户对对象和照片的对象引用是否可能搞乱绑定?

1 个答案:

答案 0 :(得分:17)

  

我不能正确地做这件事吗?

是。您正在覆盖JSON回调中的observableArray,从而销毁它:

$.getJSON(baseUri, function (data) {
    self.users = data;
});

一般来说,淘汰观察者的分配是这样的:

$.getJSON(baseUri, function (data) {
    self.users(data.$values);
});

请注意,在您的情况下,data.$values似乎包含实际数组,而不是data本身。

这适用于您的情况,但它没有充分利用淘汰赛。

为此案例创建了mapping plugin。它以递归方式遍历复杂对象,并将其所有属性转换为可观察对象,并将所有包含的数组转换为可观察数组。这使您可以对对象的状态进行细粒度控制,从而可以监视每个更改。

$.getJSON(baseUri, function (data) {
    ko.mapping.fromJS(data.$values, {}, self.users);
});

它还允许部分更新:假设您从服务器检索用户列表,并且您的视图模型已经有一半。映射插件只能添加缺少的视图模型,并对现有模型进行适当的更改。如果您想知道如何,请阅读文档中的"Advanced usage" section


假设您从服务器获取了一组用户对象并使用了映射插件,那么您的绑定将如下所示:

<ul id="update-users" data-bind="foreach: users"> 
     <li> 
            <div><div class="item">User ID</div>
                <input type="text" data-bind="value: UserId" />
            </div>                 
            <div><div class="item">Name</div>
                <input type="text" data-bind="value: Name" />
            </div>
            <ul class="photos" data-bind="foreach: Photos.$values">
              <!-- ... -->
            <ul>
     </li> 
</ul>

总的来说,@ Greg Smith的评论是正确的。尝试丢失对象键中的$,它们可能会在某些时候与敲除中的特殊变量冲突。例如,您可以安全地用下划线替换它们。

更一般地说,如果我是你,我会尝试在您的JSON中删除整个$id / $values概念,它似乎没有用于任何目的:

[
    {
        "Locations": [],
        "Photos": [],
        "UserId": 1,
        "Name": "Test User"
    }
]