您的计算的“写入”功能没有触发,因为您没有写入计算 - 这意味着在ssArray(some_value)
某处调用。
这是另一种可行的解决方案:
- 我们创建了一个 observableArray,以
items
我们各自的文本/值对命名
loadJSON
这个 observableArray 是通过手动调用来填充的。
- 我们创建了一个计算对象,它通过遍历它们来建立对
items
observableArray 以及所有项目text
和observables 的订阅。value
每当添加或删除或更改任何一项时,我们都会将整个数组序列化回 JSON
您当然可以订阅self.text
并自动触发loadJSON
,但是您必须处理触发“loadJSON”的“文本”循环,触发我们的计算,写回text
.
(我隐藏了代码片段以摆脱 HTML 和 CSS 代码块。单击“显示代码片段”运行示例。)
function MyViewModel() {
var self = this;
this.selectedItemSS = ko.observable();
this.setSelectedSS = function(item) {
self.selectedItemSS(item);
};
// Data in text form. Passed in here as a parameter from parent component
this.text = ko.observable('[{"value": "1", "text": "Low"}, {"value": "2", "text": "Medium"}, {"value": "3", "text": "High"} ]');
this.items = ko.observableArray([]);
this.loadJSON = function loadJSON(json) {
var arrayOfObjects = JSON.parse(json),
arrayOfObservables;
// clear out everything, or otherwise we'll end
// up with duplicated objects when we update
self.items.removeAll();
arrayOfObservables = ko.utils.arrayMap(arrayOfObjects, function(object) {
return {
text: ko.observable(object.text),
value: ko.observable(object.value)
};
});
self.items(arrayOfObservables);
};
this.loadJSON( this.text() );
ko.computed(function() {
var items = this.items();
// iterate over all observables in order
// for our computed to get a subscription to them
ko.utils.arrayForEach(items, function(item) {
item.text();
item.value();
});
this.text(ko.toJSON(items));
}, this);
}
ko.applyBindings(new MyViewModel());
function MyViewModel() {
var self = this;
this.selectedItemSS = ko.observable();
this.setSelectedSS = function(item) {
self.selectedItemSS(item);
};
// Data in text form. Passed in here as a parameter from parent component
this.text = ko.observable('[ \
{\
"value": "1",\
"text": "Low"\
},\
{ \
"value": "2",\
"text": "Medium"\
},\
{\
"value": "3",\
"text": "High"\
} ]');
this.items = ko.observableArray([]);
this.loadJSON = function loadJSON(json) {
var arrayOfObjects = JSON.parse(json),
arrayOfObservables;
// clear out everything, or otherwise we'll end
// up with duplicated objects when we update
self.items.removeAll();
arrayOfObservables = ko.utils.arrayMap(arrayOfObjects, function(object) {
return {
text: ko.observable(object.text),
value: ko.observable(object.value)
};
});
self.items(arrayOfObservables);
};
this.loadJSON( this.text() );
ko.computed(function() {
var items = this.items();
// iterate over all observables in order
// for our computed to get a subscription to them
ko.utils.arrayForEach(items, function(item) {
item.text();
item.value();
});
this.text(ko.toJSON(items));
}, this);
}
ko.applyBindings(new MyViewModel());
body { font-family: arial; font-size: 14px; }
.well {background-color:#eee; padding:10px;}
pre {white-space:pre-wrap;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h3>Text Json: eg from AJAX request</h3>
<p>In practice this comes from a parent custom component as a parameter</p>
<pre class="well" data-bind="text:text"></pre>
<h3>Computed data model</h3>
<p>Click on an item to edit that record</p>
<div data-bind="foreach:items" class="well">
<div data-bind="click: $parent.setSelectedSS">
<span data-bind="text:value"></span>
<span data-bind="text:text"></span><br/>
</div>
</div>
<hr/>
<h3>Editor</h3>
<div data-bind="with:selectedItemSS" class="well">
<input data-bind="textInput:value"/>
<span data-bind="text:value"></span><br/>
</div>
如果您愿意,这里有一个替代版本,它可以通过单个计算处理对 JSON 的更改以及通过接口进行的编辑:
function MyViewModel(externalObservable) {
var self = this;
this.selectedItemSS = ko.observable();
this.setSelectedSS = function(item) {
self.selectedItemSS(item);
};
// just for the demo
this.messages = ko.observableArray([]);
this.items = ko.observableArray([]);
this.json = externalObservable;
this.previous_json = '';
ko.computed(function() {
var items = this.items(),
json = this.json();
// If the JSON hasn't changed compared to the previous run,
// that means we were called because an item was edited
if (json === this.previous_json) {
var new_json = ko.toJSON(items);
self.messages.unshift("items were edited, updating JSON: " + new_json);
this.previous_json = new_json;
this.json(new_json);
return;
}
// If we end up here, that means that the JSON has changed compared
// to the last run
self.messages.unshift("JSON has changed, updating items: " + json);
var arrayOfObjects = JSON.parse(json),
arrayOfObservables;
// clear out everything, or otherwise we'll end
// up with duplicated objects when we update
this.items.removeAll();
arrayOfObservables = ko.utils.arrayMap(arrayOfObjects, function(object) {
return {
text: ko.observable(object.text),
value: ko.observable(object.value)
};
});
// iterate over all observables in order
// for our computed to get a subscription to them
ko.utils.arrayForEach(arrayOfObservables, function(item) {
item.text();
item.value();
});
this.items(arrayOfObservables);
this.previous_json = json;
}, this);
}
var externalObservableFromParam = ko.observable(),
viewModel;
// Pretend here that this observable was handed to us
// from your components' params
externalObservableFromParam('[{"value": "1", "text": "Low"}, {"value": "2", "text": "Medium"}, {"value": "3", "text": "High"} ]');
viewModel = new MyViewModel(externalObservableFromParam);
ko.applyBindings(viewModel);
function MyViewModel(externalObservable) {
var self = this;
this.selectedItemSS = ko.observable();
this.setSelectedSS = function(item) {
self.selectedItemSS(item);
};
// just for the demo
this.messages = ko.observableArray([]);
this.items = ko.observableArray([]);
this.json = externalObservable;
this.previous_json = '';
ko.computed(function() {
var items = this.items(),
json = this.json();
// If the JSON hasn't changed compared to the previous run,
// that means we were called because an item was edited
if (json === this.previous_json) {
var new_json = ko.toJSON(items);
self.messages.unshift("items were edited, updating JSON: " + new_json);
this.previous_json = new_json;
this.json(new_json);
return;
}
// If we end up here, that means that the JSON has changed compared
// to the last run
self.messages.unshift("JSON has changed, updating items: " + json);
var arrayOfObjects = JSON.parse(json),
arrayOfObservables;
// clear out everything, or otherwise we'll end
// up with duplicated objects when we update
this.items.removeAll();
arrayOfObservables = ko.utils.arrayMap(arrayOfObjects, function(object) {
return {
text: ko.observable(object.text),
value: ko.observable(object.value)
};
});
// iterate over all observables in order
// for our computed to get a subscription to them
ko.utils.arrayForEach(arrayOfObservables, function(item) {
item.text();
item.value();
});
this.items(arrayOfObservables);
this.previous_json = json;
}, this);
}
var externalObservableFromParam = ko.observable(),
viewModel;
// Pretend here that this observable was handed to us
// from your components' params
externalObservableFromParam('[{"value": "1", "text": "Low"}, {"value": "2", "text": "Medium"}, {"value": "3", "text": "High"} ]');
viewModel = new MyViewModel(externalObservableFromParam);
ko.applyBindings(viewModel);
body {
font-family: arial;
font-size: 14px;
}
.well {
background-color: #eee;
padding: 10px;
}
pre {
white-space: pre-wrap;
}
ul {
list-style-position: inside;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<h3>Text Json: eg from AJAX request</h3>
<p>In practice this comes from a parent custom component as a parameter</p>
<pre class="well" data-bind="text: json"></pre>
<textarea data-bind="value: json" cols=50 rows=5></textarea>
<h3>Computed data model</h3>
<p>Click on an item to edit that record</p>
<div data-bind="foreach: items" class="well">
<div data-bind="click: $parent.setSelectedSS">
<span data-bind="text:value"></span>
<span data-bind="text:text"></span>
<br/>
</div>
</div>
<hr/>
<h3>Editor</h3>
<div data-bind="with:selectedItemSS" class="well">
<input data-bind="textInput:value" />
<span data-bind="text:value"></span>
<br/>
</div>
<hr/>
<h3>Console</h3>
<ul data-bind="foreach: messages" class="well">
<li data-bind="text: $data"></li>
</ul>