映射和绑定嵌套对象和数组

时间:2015-11-19 09:45:58

标签: javascript arrays knockout.js mapping

我有object并且在此对象中我有项目,其中一项是array,其中还包含objects。数据样本如下所示。

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

示例数据:

"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"
                }
            ]
        }
    }

我需要找到一种方法来适当地循环这个,这样我就可以修改返回的数据,使用knockout将它绑定到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

1 个答案:

答案 0 :(得分:1)

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

我已将id作为常规属性保留,并将名称转换为可观察对象,以便可以对其进行编辑。在底部,您可以看到当前的viewmodel状态。

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

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

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

遍历每个歌手(问题中的样本数据),并为每个歌手创建一个带有id的新对象,一个包含名称的可观察对象(以及歌曲的映射,我不会在其中显示)这个片段)。

注意:我使用lodash,但许多浏览器本身支持将地图作为数组函数



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>
&#13;
&#13;
&#13;