【问题标题】:Trouble with Knockout Mapping Create/Update淘汰制映射创建/更新问题
【发布时间】:2016-09-07 12:55:50
【问题描述】:

我正在尝试映射数据,以便元素只有在值实际发生变化时才会重新呈现。

{
    Apps : [
        {
            "Categories" : [{
                    "Name" : "#Some,#More,#Tags,#For,#Measure"
                }
            ],
            "Concentrator" : "",
            "Health" : 1,
            "Id" : 2648,
            "Ip" : "1.1.1.1",
            "IsDisabled" : true,
            "IsObsolete" : false,
            "Name" : "",
            "Path" : "...",
            "SvcUrl" : "http://1.1.1.1",
            "TimeStamp" : "\/Date(1463015444163)\/",
            "Type" : "...",
            "Version" : "1.0.0.0"
        }
        ...
    ]
    ...
}

var ViewModel = function() {
    self.Apps = ko.observableArray([]);
}

var myModel = new ViewModel();

var map = {
    'Apps': {
        create: function (options) {
            return new AppModel(options.data);
        },

        key: function(data) { return ko.utils.unwrapObservable(data.Id); }
    }
}

var AppModel = function(data){
    data.Categories = data.Categories[0].Name.split(',');
    ko.mapping.fromJS(data, { }, this);
    return this;
}

function UpdateViewModel() {
    return api.getDashboard().done(function (data) {
        ko.mapping.fromJS(data, map, myModel);
    });
}

loopMe(UpdateViewModel, 5000);

function loopMe(func, time) {
    //Immediate run, once finished we set a timeout and run loopMe again
    func().always(function () {
        setTimeout(function () { loopMe(func, time); }, time);
    });
}

<script type="tmpl" id="App-template">
    <div>
        <!-- ko foreach: Categories -->
        <span class="btn btn-default btn-xs" data-bind="text:$data"></span>
        <!-- /ko -->
    </div>
</script>

在 UpdateViewModel 的第一次运行中,我将看到 5 个跨度,如预期的那样。在第二次调用中,接收到相同的数据,它被更新为一个显示 [Object object] 的跨度,这是因为它仍然认为 Categories 是一个对象数组而不是字符串数组。

如果我将地图中的“创建”更改为“更新”,一切似乎都已修复,但似乎每次都会重新渲染跨度,无论数据是否更改。

任何人都可以在我需要去的方向上帮助我,以便我可以

  1. 将类别数组从对象调整为字符串
  2. 仅重新渲染/渲染更改/新项目

这是一个 Fiddle 显示行为

【问题讨论】:

  • 我想帮忙,所以我从creating a repro based off your code开始,但发现jsfiddle根本没有任何问题? (没有“[Object object]”的麻烦,没有重新渲染类别,什么都没有。)你能解释一下我的重现出了什么问题,或者将你的代码更新为 mcve 吗?
  • @Jeroen 感谢您为我准备了小提琴。我已经编辑了你开始的地方并复制了我看到的行为。我添加了一个计数器,它刚刚切换了 fakeData,但具有相同的确切数据。

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


【解决方案1】:

问题在于这些行:

var AppModel = function(data){
    data.Categories = data.Categories[0].Name.split(','); // <-- mainly this one
    ko.mapping.fromJS(data, { }, this);
    return this;
}

有两个问题:

  1. 你改变了 data 对象,它(至少在我们的重现中)改变了 data 引用的原始对象。因此,第一次传入一个 fakeData 对象时,那个对象就发生了变异,并且将永远被“修复”。

  2. 您在 AppModel constructor 函数中对其进行变异,该函数仅在第一次调用。根据您的 key 函数,构造函数第二次应该被调用,而是 ko-mapping 应该保留原始对象并对其进行变异。但它会使用“错误”格式的 data.Categories 属性来执行此操作。

在我看来,正确的修复方法是在您的数据层中,我们在重现中已对其进行了模拟,因此我的回答向您展示如何进行是没有意义的。

另一种更老套的方法是在映射中使用update 方法,如下所示:

update: function(options) {
  if (!!options.data.Categories[0].Name) {
    options.data.Categories = options.data.Categories[0].Name.split(',');
  }
  return options.data;
},

当它遇到“未修改”的数据对象时,它会执行相同的突变。请参阅 this jsfiddle 了解该解决方案的实际效果。

【讨论】:

  • 感谢您带我到那里。我知道我在地图上做错了什么。我想我只是没有把 2 和 2 放在一起。我很感激你的时间。我将按照您的建议通过数据层解决此问题。
猜你喜欢
  • 2015-03-30
  • 2014-06-07
  • 1970-01-01
  • 2013-09-30
  • 2012-09-05
  • 2016-03-13
  • 2013-05-27
  • 2012-10-03
  • 1970-01-01
相关资源
最近更新 更多