如何使用敲除映射从空值映射到空的可观察数组?

How do you use knockout mapping to map from a null value to an empty observable array?

我在尝试使用敲除映射从空 json 属性 映射到敲除可观察数组时遇到问题。映射完成后,敲除数组为空。

因此,例如,我有以下数据:

var data = { 'Name': 'David', 'Modules': null };

以及以下型号:

var ModuleViewModel = function(data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);
};

var Model = function(data) {

    var self = this;

    var mapping = {
      'Modules': {
        key: function(module) {
            return ko.utils.unwrapObservable(module.Id);
        },
        create: function (options) {
            return new ModuleViewModel(options.data);
        }
      }
    };

    ko.mapping.fromJS(data, mapping, self);
};

然后应用到视图使用:

var model = new Model(data);
ko.applyBindings(model);

在视图中,只需:

<span data-bind="text: Name"></span>
<span data-bind="text: Modules().length"></span>

我想看到的(在我的名字之后)是已映射的模块数。如果数据中存在模块:

var data = { 'Name': 'David', 'Modules': [ {'Id': '1', 'Name': 'Module1'} ] }

然后正确的数字显示在视图上,但如果模块在数据中设置为 null,则数字根本不会显示,因为它不知道映射到可观察数组。

此外,如果我在我的视图模型上定义一个额外的 属性 映射到:

self.Modules = ko.observableArray;

这仍然没有像我预期的那样被映射,就好像你在映射之后查询 self.Modules() 你得到一个 null 返回的值,如果你查询一个普通的空可观察数组你得到 [] 返回。

我在映射中做错了什么?我只想在模块数据为空时显示 0 值。

Click here to edit using jsbin

您可以放置​​一个计算的可观察对象进行空值检查并尽可能保持干净,如下所示:

var ModuleViewModel = function(data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);
    //After mapping the object, add the computed observable here
    self.numberOfModules = ko.computed(function() {
        return this.Modules ? this.Modules().length : 0;
    }, self);
};

然后在你的绑定中:

<span data-bind="text: numberOfModules">

如果 computed 在 HTML 中的许多不同地方使用以避免在任何地方重复空检查,这将特别方便。

这里有一些您可能会觉得有用的映射更新。

http://jsbin.com/zeguxiveyi/1

请务必注意以下更改。

一方面,您没有应用映射。

// need to invoke the mapping object
ko.mapping.fromJS(data, mapping, self);

其次,用 null 调用 observable 没有多大意义……这就像吃甜甜圈的洞,对吧?

//Initialize your data with null modules :: ERROR
//For the sake of having an empty observable array, we need to convert this null to an empty array
var data = { 'Name': 'David', 'Modules': null };
if(data.Modules == null) data.Modules = [];

第三,如果你可能得到空值,你应该继续添加一点短路逻辑来防止它...

var mapping = {
 'Modules': {
    create: function (options) {
      if(options.data !== null)
        return new ModuleViewModel(options.data);
    }
  }
};

总而言之,地图插件很好用,但没有什么神奇的地方……还是要确保你的数据是合理的。