【问题标题】:How do you use knockout mapping to map from a null value to an empty observable array?你如何使用淘汰映射从一个空值映射到一个空的可观察数组?
【发布时间】:2015-05-24 03:51:42
【问题描述】:

当我尝试使用敲除映射从空 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

【问题讨论】:

  • 您可以更改绑定。 &lt;span data-bind="text: (Modules() || []).length"&gt;&lt;/span&gt;
  • 你可以,但这并不能真正帮助他进行映射操作
  • 当然,我只是想指出您不一定需要更改映射以使绑定正常工作。有时最好让您的绑定足够灵活以使用不同的映射。
  • 当您使用映射插件时,您不能拥有nullundefined 值,该插件只有在键具有值时才能工作。如果你想正确使用它,你需要确保你确实有数据。
  • @JeffMercado Null 也是数据,属性值可以在有值和为空之间变化。这是糟糕的设计。

标签: javascript knockout.js knockout-mapping-plugin


【解决方案1】:

以下是对您的映射的一些更新,您可能会觉得有用。

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

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

【讨论】:

  • 关于您的第一点,我已经更新了问题和小提琴以包含映射。这只是创建小提琴时的另一个错误。
  • 关于你的第二点,你的权利,我正在努力迎合不良数据。我现在意识到我的数据应该是var data = { 'Name': 'David', 'Modules': []};,带有一个空数组而不是空数组。我已经回到源头以确保在我的数据被序列化时提供一个空数组。这样,我就不必提供这些前端解决方法。
  • 你的第二点:当然可以,如果你有一个对象,其中一个属性可以在对象和 null 之间改变,重新映射它会破坏 observable 并因此与订阅者的所有连接财产。不得不手动检查这些情况很糟糕。
【解决方案2】:

您可以放置​​一个计算出的 observable 用于 null 检查并尽可能保持其干净,如下所示:

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 中的许多不同地方使用了计算,这将特别方便,以避免在各处重复空检查。

【讨论】:

  • 感谢您的回答。我确实曾经有过类似的事情,但确实感觉有些不对劲。在 beauXjames 回答之后,我意识到这是错误的源数据,当我将数据更正为空数组 [] 而不是 null 时,我的所有问题都消失了。不过感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 2012-10-14
  • 1970-01-01
  • 2017-08-11
  • 2012-05-14
  • 2013-03-12
  • 2012-11-08
  • 1970-01-01
  • 2012-06-01
相关资源
最近更新 更多