Отображение и привязка нокаута
У меня есть некоторые проблемы с вложенными моделями представления в нокауте с использованием подключаемого модуля. Я могу воссоздать проблему, и я создал для нее скрипку: Fiddle
Я сократил фактическое представление и модель представления, так что не ожидайте, что результат будет выглядеть хорошо, но он получит сообщение в полном объеме. Это мой взгляд:
<div data-bind="foreach: $root.selectedArmy().Units">
<div class="unitoverview">
<!-- ko foreach: UnitMembers-->
<div class="member">
<div>
<span class="name" data-bind="text: Name, click: $parent.RemoveTest"></span>
</div>
<div data-bind="foreach: test">
<span data-bind="text:$data, click: $parent.RemoveTest"></span>
</div>
<h1 data-bind="text: test2"></h1>
</div>
<!-- /ko -->
</div>
</div>
<span data-bind="click:AddUnit">CLICK TO ADD UNIT</span>
И это моя модель:
var armymaker = armymaker || {};
var unitMapping = {
'UnitMembers': {
create: function (options) {
return new UnitMemberViewModel(options.data);
}
}
};
var UnitViewModel = function (unit) {
var self = this;
self.Name = ko.observable("unitname");
self.UnitDefinitionId = ko.observable(unit.Id);
ko.mapping.fromJS(unit, {}, self);
};
var UnitMemberViewModel = function (unitmemberdefinition) {
var self = this;
self.test = ko.observableArray([ko.observable('TEST'), ko.observable('TEST2')]);
self.test2 = ko.observable('TEST1');
self.RemoveTest = function () {
self.test.splice(0,1);
self.Name('BUGFACE');
self.test2('OKI!!');
};
ko.mapping.fromJS(unitmemberdefinition, {}, self);
};
var ViewModel = function () {
var self = this;
self.showLoader = ko.observable(false);
self.newArmy = ko.observable({});
self.unitToAdd = ko.observable(null);
self.selectedArmy = ko.observable({ Template: ko.observable(''), Units: ko.observableArray() });
self.AddUnit = function () {
var data = {'Name': 'My name', 'UnitMembers': [
{ 'Name': 'Unitname1' }
] };
self.unitToAdd(new UnitViewModel((ko.mapping.fromJS(data, unitMapping))));
self.selectedArmy().Units.push(self.unitToAdd());
self.unitToAdd(null);
};
};
armymaker.viewmodel = new ViewModel();
ko.applyBindings(armymaker.viewmodel);
Что происходит, это следующее:
Я нажимаю на ссылку НАЖМИТЕ, ЧТОБЫ ДОБАВИТЬ ЕДИНИЦУ, и это создало UnitViewModel
и для каждого элемента в UnitMember
массив будет использовать UnitMemberViewModel
из-за кастомного переплета (unitMapper
) что я использую.
Кажется, все это работает нормально. Однако в самой внутренней модели представления я добавляю некоторое поле к модели данных. Я позвонил им test
это observableArray
, а также test2
это обычный observable
, Я также создал метод под названием RemoveTest
который связан в представлении как промежуток, который представляет test2
и промежуток в foreach
которые представляют каждый элемент массива test
,
Однако, когда я вызываю метод, изменение observable
отражается в представлении, но без изменений observableArray
виден на виде. Проверьте скрипку для деталей.
Есть ли причины, по которым изменения в obsArray
не будет виден в представлении, но меняется на обычный observable
будут?
Я сделал несколько замечаний:
- Событие клика на
observable
не работает, только событие click на элементах наobservableArray
, - Кажется, что self внутри события click не соответствует фактической модели представления. Если я пойду
self.test.splice(0,1)
ничего не происходит в представлении, ноself.test.splice
содержит только один элемент после этой команды. Однако, если я пересечу базовую модель вида (armymaker.viewmodel.Units()[0].UnitMembers()[0].test
) по-прежнему содержит два элемента. - Вызов соединения на пройденной модели просмотра (
armymaker.viewmodel.Units()[0].UnitMembers()[0].test.splice(0,1)
) удаляет элемент из представления, поэтому в некотором роде кажется, что элемент, на который ссылается self, не является тем же объектом, что и связанный внутри представления. Но тогда, почему это работает дляobservable
это неarray
?
Возможно, в моей модели есть недостаток, но я не вижу его, поэтому буду признателен за помощь.
1 ответ
Вы в основном "двойное отображение".
Сначала с
self.unitToAdd(new UnitViewModel((ko.mapping.fromJS(data, unitMapping))));
и второй раз внутри UnitViewModel
:
ko.mapping.fromJS(unit, {}, self);
где unit
уже ko.mapping
Созданный полный "UnitViewModel", это двойное отображение приводит ко всем вашим проблемам.
Чтобы это исправить, вам просто нужно удалить первое сопоставление:
self.unitToAdd(new UnitViewModel(data));
self.selectedArmy().Units.push(self.unitToAdd());
self.unitToAdd(null);
и использовать опцию отображения внутри UnitViewModel
:
var UnitViewModel = function (unit) {
var self = this;
self.Name = ko.observable("unitname");
self.UnitDefinitionId = ko.observable(unit.Id);
ko.mapping.fromJS(unit, unitMapping, self);
};
Демо JSFiddle.
SideNote, чтобы исправить проблему "событие щелчка на наблюдаемой не работает", вам просто нужно удалить $parent
:
<span class="name" data-bind="text: Name, click: RemoveTest"></span>
потому что вы уже в контексте одного UnitMemberViewModel
,