具有对象集合的Json数据被映射为可观察的而不是可观察的数组

时间:2014-04-14 08:12:51

标签: javascript html5 knockout.js collections mapping

在我的页面上,我想通过Json接收用户帐户的viewmodel。数据包括一些用户详细信息,如真实姓名和电子邮件地址等。除此之外,我还需要显示(和更改)特定用户所属的组,以及所有可用用户组的列表以选择其他为用户提供的。

正确加载数据并按预期显示用户详细信息。对于组分配,我创建了两个列表框。第一个显示当前分配的组,另一个显示所有现有组。我想使用两个按钮将所选项目从“所有组”列表移动到“选定组”列表(“添加到选择”),另一个按钮从“选定组”列表中删除项目并将其放回进入“所有群组”列表。

两个列表都已正确填充。当我在运行时查看我的viewModel时,我可以看到viewModel.AllGroups()是一个可观察的,在_latestValues中有一些 group 对象(一个组对象由一个 Id 和 GroupName )。我也可以直接正确访问它们,例如点击按钮进行测试触发

alert(viewModel.AllGroups()[0].GroupName());

这给出了正确的文字,所以基本上一切都已到位。但是当我尝试手动将组对象添加到SelectedGroups集合时,似乎viewModel.SelectedGroupsviewModel.AllGroups没有.push.remove,因为它们不是一个可观察的数组,但只是一个可观察的数据!?

这是我的JS代码:

<script type="text/javascript">
    var viewModel;

    $(function () {

        $.ajaxSetup({ cache: false });

        $.getJSON('/Admin/GetEditWebUserData?Id=@WebUserId', function (data) {
            viewModel = ko.mapping.fromJS(data);
            Selected = viewModel.SelectedGroups();

            viewModel.addToSelection = function () {
                viewModel.SelectedGroups().push({ GroupName: 'Test Group', Id: '123' });
            }

            ko.applyBindings(viewModel, document.getElementById('data'));
        });
    });
</ script>

...这里是带有绑定的HTML部分:

<div id="data">
    <div class="WebUserGroupEditBox">
        Member of:
        <select size="5" data-bind="options: SelectedGroups(), optionsText: 'GroupName', optionsValue: 'Id'"></select>
        <button data-bind="click: removeFromSelection">remove from selection</button>
    </div>
    <div class="WebUserGroupEditBox">
        Available groups:
        <select multiple="multiple" size="5" data-bind="options: AllGroups(), optionsText: 'GroupName', optionsValue: 'Id'"></select>
        <button data-bind="click: addToSelection">add to selection</button>
    </div>
</div>

当我点击添加到选择按钮时,出现错误,告诉我.push不存在。我认为这可能是映射问题。除了自己实现映射外,还有什么我可以做的吗?

更新:这是一些Json数据(直接从服务器响应中嗅探):

{
   "FirstName":"Rob",
   "LastName":"Smith",
   "UserName":"rsmith",
   "Email":"rsmith@test.com",
   "SelectedGroups":null,
   "AllGroups":[
      {
         "Id":0,
         "GroupName":"Managers",
         "AllowCommands":true,
         "AllowParameters":true
      },
      {
         "Id":1,
         "GroupName":"Guests",
         "AllowCommands":false,
         "AllowParameters":false
      }
   ]
}

解决方案:

问题不在于映射本身,而在于构造Json数据的服务器端代码。正如nemesv在他的评论中指出的那样,当没有项目时,需要有一个空数组而不是null,以便映射插件正确识别数据的结构。

1 个答案:

答案 0 :(得分:0)

问题在于你的JSON来自服务器:

"SelectedGroups":null,

由于您的属性为null,因此映射插件无法在此处创建数组,因此只需为您创建ko.observable

要解决此问题,您需要更改服务器端以发送空数组而不是null

"SelectedGroups": [],

在这种情况下,映射插件将创建一个空的ko.observableArray

但是,如果您无法更改服务器端,您还可以告诉映射插件如何使用create mapping option映射"SelectedGroups"属性:

var mapping = {
    "SelectedGroups": {
        create: function(options){
            if (!options.data) // no data from the server return an empty array
                return ko.observableArray();
            // SelectedGroups is not empty continue the mapping
            return ko.mapping.fromJS(options.data);
        }
    }
};

var vm = ko.mapping.fromJS(data, mapping);

演示JSFiddle