Отображение и привязка нокаута

У меня есть некоторые проблемы с вложенными моделями представления в нокауте с использованием подключаемого модуля. Я могу воссоздать проблему, и я создал для нее скрипку: 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,

Другие вопросы по тегам