Knockout Mapping创建/更新有问题

时间:2016-05-11 22:19:05

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

我正在尝试映射数据,以便在值实际更改时仅重新呈现元素。

{
    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. 将Categories数组从对象调整为字符串
  2. 仅重新渲染/渲染已更改/新项目
  3. 以下是显示行为的Fiddle

1 个答案:

答案 0 :(得分:1)

问题出在这些方面:

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

有两个问题:

  1. 你改变data对象(至少在我们的repro中)会改变data引用的原始对象。因此,第一次传入一个fakeData对象时,会对其进行一次变异,并且永远会被修复为#34;。

  2. 您在AppModel 构造函数函数中对其进行了变异,这只是第一次调用。根据你的key函数,第二次构造函数应该被调用,而是ko-mapping应该保留原始对象并将其变异。但它会用错误的&#34;#34;格式化data.Categories属性。

  3. 在我看来,正确的解决方案是在你的数据层中,我们在repro中嘲笑过,所以我的答案向你展示如何做是没有意义的。

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

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

    遇到&#34;未经修改的&#34;数据对象它会做同样的突变。有关该解决方案的实施情况,请参阅this jsfiddle