Когда вы изменяете значение <select>
с помощью кода, нокаут ищет новое значение в списке options
, чтобы он мог обновить пользовательский интерфейс.
Когда вы устанавливаете currentPerson
(который связан с value
) на что-либо, что не присутствует в массиве persons
(который связан с options
), пользовательский интерфейс будет не обновляется.
Когда вы сохраняете человека, вы сериализуетесь в JSON. После реконструкции вы получите новый объект, который нокаутом не может совпасть с ранее связанными параметрами.
Существует два возможных решения:
- Используйте привязку
optionsValue
, чтобы нокаут использовал свойство id
для сопоставления лиц, а не проверки экземпляра, или
- Выполните ручной поиск ранее созданной модели представления при загрузке человека.
Я реализовал решение 2 в следующем примере.
var currentPersonAsJson = null;
var handlerVM = function () {
var self = this;
self.persons = ko.observableArray([
new PersonVM("john", 1),
new PersonVM("paul", 2),
new PersonVM("viki", 3),
]);
self.currentPerson = ko.observable();
self.save = function () {
currentPersonAsJson = ko.toJSON(self.currentPerson);
console.log(currentPersonAsJson);
}
self.load = function () {
var loadedPerson = ko.mapping.fromJSON(currentPersonAsJson);
// loadedPerson is a new instance, so it won't match anything
// inside self.persons
// Let's do a manual lookup:
var matchedVM = self.persons().find(
p => p.id() === loadedPerson.id
);
if (matchedVM) {
loadedPerson = matchedVM;
}
// Edge case: We've loaded something that we don't know:
else {
self.persons.push(loadedPerson);
}
self.currentPerson(loadedPerson);
}
self.log = function () {
console.log(ko.toJSON(self.currentPerson));
}
}
var PersonVM = function (name, id) {
var self = this;
self.name = ko.observable(name);
self.id = ko.observable(id);
}
var handler = new handlerVM();
ko.applyBindings(handler);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://rawgit.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js
"></script>
<div>
<div>
<select data-bind="options: persons,
optionsText: 'name',
optionsCaption: 'choose a person',
value: currentPerson"
>
</select>
</div>
<div>
<button data-bind="text: 'save', click: save" />
<button data-bind="text: 'load', click: load" />
<button data-bind="text: 'log current person', click: log" />
</div>
</div>
Редактирование бонуса: решение 1 :
var currentPersonAsJson = null;
var handlerVM = function () {
var self = this;
self.persons = ko.observableArray([
new PersonVM("john", 1),
new PersonVM("paul", 2),
new PersonVM("viki", 3),
]);
self.currentPerson = ko.observable();
self.save = function () {
currentPersonAsJson = ko.toJSON(self.currentPerson);
console.log(currentPersonAsJson);
}
self.load = function () {
self.currentPerson(currentPersonAsJson);
}
self.log = function () {
console.log(ko.toJSON(self.currentPerson));
}
}
var PersonVM = function (name, id) {
var self = this;
self.name = ko.observable(name);
self.id = ko.observable(id);
}
var handler = new handlerVM();
ko.applyBindings(handler);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://rawgit.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js
"></script>
<div>
<div>
<select data-bind="options: persons,
optionsText: 'name',
optionsCaption: 'choose a person',
value: currentPerson,
optionsValue: 'id'"
>
</select>
</div>
<div>
<button data-bind="text: 'save', click: save" />
<button data-bind="text: 'load', click: load" />
<button data-bind="text: 'log current person', click: log" />
</div>
</div>