Knockout.js: вызывать функцию на прототипе, но оставаться в контексте foreach

Я пытаюсь создать простую игру в крестики-нолики с использованием knockout.js. Я также использую Jade в качестве препроцессора; дайте мне знать, если вас это смущает, но это должно быть довольно просто.

Поэтому мне нужно использовать функцию для моих объектов в моей привязке данных foreach в моем HTML, но мне также нужно иметь доступ к другим объектам в viewModel. Я не совсем уверен, как это сделать. Я могу получить доступ к функции, если я помещу ее в объекты в foreach, но тогда я не могу получить доступ к объектам вне этого объекта.

Итак, мой вопрос: как мне вызвать функцию из контекста foreach, который имеет доступ ко всему на viewModel?

Вот мой код:

HTML

table.bg-success(style="table-layout:fixed;")
  tr#row1(data-bind="foreach:topRow")

    td(data-bind="text:symbol,click:function(){$parent.PlayerTurn.bind($root)();$root.changeSymbol()}")

  tr#row2(data-bind="foreach:middleRow")
    td(data-bind="text:symbol,click:function(){$parent.PlayerTurn.bind($root)();$root.changeSymbol()}") 

  tr#row3(data-bind="foreach:bottomRow")
    td(data-bind="text:symbol,click:function(){$parent.PlayerTurn.bind($root)();$root.changeSymbol()}")

JAVASCRIPT

var aBox = (function(position){
  function ABox(){
    this.symbol = ko.observable("");
    this.position = position
    this.count = 0;

  }

  return ABox;
})()

var viewModel = (function(){
  function ViewModel(){
    this.theMessage = new message();
    this.thePlayers = new players();
    this.topRow = ko.observableArray([
      new aBox("r1c1"),
      new aBox("r1c2"),
      new aBox("r1c3"),     
    ]);
    this.middleRow = ko.observableArray([
      new aBox("r2c1"),
      new aBox("r2c2"),
      new aBox("r2c3"),
    ]);
    this.bottomRow = ko.observableArray([
      new aBox("r3c1"),
      new aBox("r3c2"),
      new aBox("r3c3"),
    ]);     
  }

    ViewModel.prototype.changeSymbol = function(){
      this.count+=1;
      if(this.count%2==0){
      this.symbol("O");
      }else{
        this.symbol("X")
      }
    }    

  return ViewModel;
})()

ko.applyBindings(new viewModel())

1 ответ

Решение

Привыкайте помещать всю логику в модель представления / javascript, а не в представление. Кроме того, прочитайте click Обязательная документация обработчика, на самом деле она отвечает на большинство ваших вопросов и является лишь кратким чтением.

В основном это:

td(data-bind="text:symbol, click: $root.changeSymbol") 

Тогда вы можете включить эту функцию $root:

var self = this;
self.changeSymbol = function(childVm) {
  console.log(self); // is the $root
  console.log(childVm); // the item from the foreach
}

Если вам нужно получить доступ к элементам между "потомком" и "корнем" (то есть там лежит $parent между) вы должны либо:

  • Переместить changeSymbol функция к $parent и убедитесь, что модель родительского представления имеет ссылку на своего родителя, если вам нужно использовать это внутри функции; или же
  • Поместите свойство для родителя в дочерний vm, чтобы функция могла вызывать childVm.parent чтобы добраться до этой модели представления.

Как примечание ноги, если вам абсолютно необходимо, вы можете сделать это:

td(data-bind="text:symbol, click: function() { $root.changeSymbol($root, $parent, $data); }") 

Но это, вероятно, означает, что у вас есть проблема XY, и ваши модели представлений не структурированы так, как они должны быть.

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