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

Javascript 如何使用敲除映射将空值映射到空的可观察数组?,javascript,knockout.js,knockout-mapping-plugin,Javascript,Knockout.js,Knockout Mapping Plugin,当我试图使用knockout映射将空json属性映射到knockout可观测数组时,我遇到了一个问题。执行映射后,敲除数组为空 例如,我有以下数据: var data = { 'Name': 'David', 'Modules': null }; 以及以下型号: var ModuleViewModel = function(data) { var self = this; ko.mapping.fromJS(data, {}, self); }; var Model = fu

当我试图使用knockout映射将空json属性映射到knockout可观测数组时,我遇到了一个问题。执行映射后,敲除数组为空

例如,我有以下数据:

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>
然后在视图上显示正确的数字,但如果模块在数据中设置为null,则该数字根本不显示,因为它不知道映射到可观察阵列

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

self.Modules = ko.observableArray;
这仍然没有像我期望的那样得到映射,就像您查询
self.Modules()
在映射之后,当您查询一个正常的空可观察数组时,返回一个
null
值一样

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


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

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


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

下面是对映射的一些更新,您可能会发现这些更新很有用

重要的是要注意以下变化

首先,您没有应用映射

// need to invoke the mapping object
ko.mapping.fromJS(data, mapping, self);
其次,用null调用一个可观察对象没有多大意义……这就像吃甜甜圈的洞,对吗

//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);
    }
  }
};

总而言之,映射插件是有用的,但它并没有什么神奇之处……仍然需要确保您的数据是合理的

您可以更改您的绑定<代码>可以,但这并不能真正帮助他进行映射操作。当然,我只是想指出,您不一定需要更改映射以使绑定正常工作。有时,最好使绑定足够灵活,以处理不同的映射。当您使用映射插件时,不能有
null
未定义的值,该插件仅在键有值时才工作。如果要正确使用数据,您需要确保您实际拥有数据。@JeffMercado Null也是数据,属性值在有值和为Null之间可能有所不同。这是一个糟糕的设计。关于你的第一点,我已经更新了问题和小提琴,包括映射。这只是制作小提琴时的另一个错误。关于你的第二点,你的权利,我试图迎合坏数据。我现在意识到我的数据应该是
var data={'Name':'David','Modules':[]}使用空数组而不是空数组。我回到了源代码,以确保在序列化数据时提供空数组。这样,我就不必提供这些前端解决方法。你的第二点:当然可以,如果你有一个对象,其中一个属性可以在对象和null之间进行更改,那么重新映射它将破坏可观察的对象,并因此破坏与该属性订阅者的所有连接。必须手动检查这些案例很糟糕。谢谢你的回答。我确实有过类似的经历,但确实感觉有点不对劲。根据beauXjames的回答,我意识到源数据是错误的,当我将数据更正为空数组[]而不是空数组[]时,我的所有问题都消失了。谢谢你的回答。
var mapping = {
 'Modules': {
    create: function (options) {
      if(options.data !== null)
        return new ModuleViewModel(options.data);
    }
  }
};