【问题标题】:Mapping and binding nested objects and arrays映射和绑定嵌套对象和数组
【发布时间】:2016-02-21 09:07:17
【问题描述】:

我有一个object,在这个对象中我有项目,其中一个项目是array,其中还包含objects。数据示例如下所示。

我正在使用敲除将此数据绑定到视图,因此我认为我需要实现一个双循环来返回子数组中的对象和对象,以便能够将它们绑定到视图中。

样本数据:

"singers": {
        "ijiyt6ih": {
            "id": ObjectId('ijiyt6ih'),
            "name": "John",
            "songs": [
                {
                    "id": ObjectId('okoiu8yi'),
                    "songName": "Hello There",
                    "year": "1980"
                },
                {
                    "id": ObjectId('sewfd323'),
                    "songName": "No More",
                    "year": "1983"
                }
            ]
        },
        "98usd96w": {
            "id": ObjectId('98usd96w'),
            "name": "Jack",
            "songs": [
                {
                    "id": ObjectId('iew342o3'),
                    "songName": "Hurry Up",
                    "year": "1985"
                }
            ]
        }
    }

我需要找到一种方法来适当地循环遍历它,以便我可以修改返回的数据以使用敲除将其绑定到 viewModel。

这是我的 viewModel 的样子:

singersViewModel = function(data) {
   var self = {
           singerId: ko.observable(data.id),
           singerName: ko.observable(data.name),
           songName: ko.observable(...),
           songYear: ko.observable(...)
       };

我不确定是否必须返回两组不同的数据。

至于循环。我能够循环并返回要在页面上显示的歌手列表,但我无法获取每个歌手中显示的歌曲列表。

到目前为止,这是我的循环:

var self = {},
    singer,
    tempSingers = [];

    self.singers = ko.observableArray([]);
    for (singer in singers) {
        if (singers.hasOwnProperty(singer)) {
             tempSingers.push(new singersViewModel(singers[singer]));
           }
     }
     self.singers(tempSingers);

我尝试在此循环中为歌曲复制相同类型的循环,但使用 hasOwnProperty 会出错,因为歌曲是 array

【问题讨论】:

标签: javascript arrays knockout.js mapping


【解决方案1】:

在包含的 sn-p 中,您可以看到如何将原始数据映射到可以绑定到视图的视图模型。

我将 id 保留为常规属性,并将名称转换为 observable,以便可以对其进行编辑。在底部您可以看到当前的视图模型状态。

还有一个迭代歌手列表的示例视图,以及每个歌手中的歌曲列表。

如您所见,我正在使用映射来实施解决方案。对于映射,您需要实现一个回调来接收每个原始对象并返回一个具有新结构的新对象。比如这部分代码

_.map(_singers, function(singer) {
    return {
      id: singer.id,
      name: ko.observable(singer.name),
      // ... songs: 
})

遍历每个歌手(问题中的示例数据),并为每个歌手创建一个带有 id 的新对象,一个包含名称(和歌曲映射,我没有在这个片段中显示的)的 observable )。

注意:我使用的是lodash,但许多浏览器原生支持 map 作为数组函数

var ObjectId = function (id) { return id; }

var singers = {
        "ijiyt6ih": {
            "id": ObjectId('ijiyt6ih'),
            "name": "John",
            "songs": [
                {
                    "id": ObjectId('okoiu8yi'),
                    "songName": "Hello There",
                    "year": "1980"
                },
                {
                    "id": ObjectId('sewfd323'),
                    "songName": "No More",
                    "year": "1983"
                }
            ]
        },
        "98usd96w": {
            "id": ObjectId('98usd96w'),
            "name": "Jack",
            "songs": [
                {
                    "id": ObjectId('iew342o3'),
                    "songName": "Hurry Up",
                    "year": "1985"
                }
            ]
        }
    };

var SingersVm = function(_singers) {
  var self = this;
  self.singers = _.map(_singers, function(singer) {
    return {
      id: singer.id,
      name: ko.observable(singer.name),
      songs: _.map(singer.songs, function(song) {
        return {
          name: ko.observable(song.songName),
          id: song.id
          };
        })
    };
  });
  return self;
};

var vm = new SingersVm(singers);
//console.log(vm);
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div data-bind="foreach: singers">
  <div>
      <input data-bind="value: name"/> (<span data-bind="text: id"></span>)
      <ul data-bind="foreach:songs">
        <li>
          <input data-bind="value: name"/> (<span data-bind="text: id"></span>)
        </li>
      </ul>
  </div>
</div>
        
<pre data-bind="html: ko.toJSON($root,null,2)">
</pre>

【讨论】:

  • 这是我以前没有考虑过的一种新颖而简洁的方法,感谢分享。但是是否有可能以不同的方式使其更通用,因为可以使用更多项目更新数据库,这意味着我每次都必须更新代码。我一直在寻找一种方法来循环遍历这些项目,无论它们是什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-08
  • 2023-01-23
  • 2021-09-30
  • 1970-01-01
  • 2022-08-10
  • 2021-06-23
  • 2020-09-27
相关资源
最近更新 更多