Javascript 敲除映射创建/更新有问题

Javascript 敲除映射创建/更新有问题,javascript,knockout.js,knockout-mapping-plugin,Javascript,Knockout.js,Knockout Mapping Plugin,我正在尝试映射数据,以便仅当值实际发生更改时才重新渲染元素 { Apps : [ { "Categories" : [{ "Name" : "#Some,#More,#Tags,#For,#Measure" } ], "Concentrator" : "", "Health" : 1,

我正在尝试映射数据,以便仅当值实际发生更改时才重新渲染元素

{
    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>
{
应用程序:[
{
“类别”:[{
“名称”:“#一些,#更多,#标记,#用于,#度量”
}
],
“集中器”:“,
"健康":一,,
“Id”:2648,
“Ip”:“1.1.1.1”,
“IsDisabled”:正确,
“Isobsolite”:假,
“名称”:“,
“路径”:“…”,
“SvcUrl”:”http://1.1.1.1",
“时间戳”:“\/日期(1463015444163)\/”,
“类型”:“…”,
“版本”:“1.0.0.0”
}
...
]
...
}
var ViewModel=函数(){
self.Apps=ko.observearray([]);
}
var myModel=new ViewModel();
变量映射={
“应用程序”:{
创建:函数(选项){
返回新的AppModel(options.data);
},
键:函数(数据){return ko.utils.unwrapobbservable(data.Id);}
}
}
var AppModel=函数(数据){
data.Categories=data.Categories[0].Name.split(',');
fromJS(数据,{},this);
归还这个;
}
函数UpdateViewModel(){
返回api.getDashboard().done(函数(数据){
fromJS(数据、地图、myModel);
});
}
loopMe(UpdateViewModel,5000);
函数loopMe(函数,时间){
//立即运行,完成后,我们设置超时并再次运行loopMe
func().始终(函数(){
setTimeout(函数(){loopMe(func,time);},time);
});
}
在UpdateViewModel的第一次运行中,我将看到预期的5个跨度。在第二次调用中,接收到相同的数据,它被更新为一个称为[Object Object]的范围,这是因为它仍然认为类别是一个对象数组,而不是字符串数组

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

谁能帮我一把,让我朝着我要去的方向走

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

  • 下面是一个显示行为的示例

    问题在于这些行:

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

    当它遇到一个“未修改”的数据对象时,它将执行相同的变异。请参阅,以了解实际的解决方案。

    我想提供帮助,所以我从开始,但发现JSFIDLE根本没有显示任何问题?(没有“[对象]”麻烦,没有重新渲染类别,什么都没有。)你能解释一下我的复制哪里出错了,或者把你的代码更新成mcve吗?@Jeroen谢谢你帮我做了一把小提琴。我已经编辑了你开始的地方,并复制了我看到的行为。我添加了一个计数器,可以切换伪造的数据,但是数据是一样的。谢谢你帮我找到了。我知道我把地图弄错了。我想我只是没有把2和2放在一起。谢谢你抽出时间。我将按照您的建议,通过数据层解决这个问题。
    update: function(options) {
      if (!!options.data.Categories[0].Name) {
        options.data.Categories = options.data.Categories[0].Name.split(',');
      }
      return options.data;
    },