敲除映射问题 Create/Update
Trouble with Knockout Mapping Create/Update
我正在尝试映射数据,以便仅在值实际更改时才重新呈现元素。
{
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 是一个对象数组而不是一个字符串数组。
如果我在我的地图中将 'create' 更改为 'update',一切似乎都已修复,但是无论数据是否更改,似乎每次都会重新渲染跨度。
任何人都可以帮我指明我需要去的方向,这样我就可以
- 将类别数组从对象调整为字符串
- 只有 re-render/render changed/new 项
这里是 Fiddle 显示行为
问题在于这些行:
var AppModel = function(data){
data.Categories = data.Categories[0].Name.split(','); // <-- mainly this one
ko.mapping.fromJS(data, { }, this);
return this;
}
有两个问题:
你改变了 data
对象,它(至少在我们的 repro 中)改变了 data
引用的原始对象。所以第一次传入一个 fakeData 对象时,那个对象就地改变了,并且永远是 "fixed".
你在AppModel
constructor函数中改变它,它只被第一次调用。根据您的 key
函数,第二次构造函数应该 而不是 被调用,而是 ko-mapping 应该保留原始对象并在适当的位置进行变异。但它会使用 "wrongly" 格式 data.Categories
属性.
在我看来,正确的修复是在您的数据层中,我们已在重现中对其进行了模拟,因此我的回答向您展示如何操作毫无意义。
另一种更 hacky 的方法是在映射中使用 update
方法,如下所示:
update: function(options) {
if (!!options.data.Categories[0].Name) {
options.data.Categories = options.data.Categories[0].Name.split(',');
}
return options.data;
},
当它遇到一个 "unmodified" 数据对象时,它会做同样的改变。请参阅 this jsfiddle 以了解实际的解决方案。
我正在尝试映射数据,以便仅在值实际更改时才重新呈现元素。
{
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 是一个对象数组而不是一个字符串数组。
如果我在我的地图中将 'create' 更改为 'update',一切似乎都已修复,但是无论数据是否更改,似乎每次都会重新渲染跨度。
任何人都可以帮我指明我需要去的方向,这样我就可以
- 将类别数组从对象调整为字符串
- 只有 re-render/render changed/new 项
这里是 Fiddle 显示行为
问题在于这些行:
var AppModel = function(data){
data.Categories = data.Categories[0].Name.split(','); // <-- mainly this one
ko.mapping.fromJS(data, { }, this);
return this;
}
有两个问题:
你改变了
data
对象,它(至少在我们的 repro 中)改变了data
引用的原始对象。所以第一次传入一个 fakeData 对象时,那个对象就地改变了,并且永远是 "fixed".你在
AppModel
constructor函数中改变它,它只被第一次调用。根据您的key
函数,第二次构造函数应该 而不是 被调用,而是 ko-mapping 应该保留原始对象并在适当的位置进行变异。但它会使用 "wrongly" 格式data.Categories
属性.
在我看来,正确的修复是在您的数据层中,我们已在重现中对其进行了模拟,因此我的回答向您展示如何操作毫无意义。
另一种更 hacky 的方法是在映射中使用 update
方法,如下所示:
update: function(options) {
if (!!options.data.Categories[0].Name) {
options.data.Categories = options.data.Categories[0].Name.split(',');
}
return options.data;
},
当它遇到一个 "unmodified" 数据对象时,它会做同样的改变。请参阅 this jsfiddle 以了解实际的解决方案。