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

Json data with collection of objects gets mapped as observable instead of observable array

本文关键字:观察 数组 映射 对象 集合 Json 数据      更新时间:2023-09-26

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

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

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

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,这样映射插件才能正确识别数据的结构。

问题出在来自服务器的JSON中:

"SelectedGroups":null,

因为你的属性是null,所以映射插件不知道你想要一个数组,它只是为你创建了一个ko.observable

要修复它,您需要更改服务器端以发送一个空数组,而不是null:

"SelectedGroups": [],

在这种情况下,映射插件将创建一个空的CCD_。

但是,如果您不能更改服务器端,您也可以告诉映射插件如何使用create映射选项来映射"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。