2016-01-23 4 views
0

У меня есть таблица, которую я заполняю некоторыми номерами. В каждой строке есть кнопка. После нажатия этой кнопки я хотел бы уменьшить счетчик в этой строке. Как к этому с нокаутом?Уменьшить значение после нажатия кнопки в той же строке - нокаут

<div class="panel panel-default"> 
    <div class=panel-heading>Title</div> 
    <table class=table> 
     <thead> 
      <tr> 
       <th>Counter</th> 
       <th>Increment</th>     
      </tr> 
     </thead> 
     <tbody data-bind="foreach: records"> 
     <tr> 
      <td data-bind="text: counter"></td>    
      <td> <input type="button" value="increment" data-bind=??? ></td> 
     </tr> 
    </tbody> 
    </table> 
</div> 

<script> 
function AppViewModel() { 
    var self = this; 
    self.records = ko.observableArray([]); 

    $.getJSON("/data", function(data) {   
     self.records(data);  
    }) 

//function to decrement 

} 

ko.applyBindings(new AppViewModel()); 
</script> 

ответ

1

Я хотел бы сделать это следующим образом:

  1. процессом данных, которые вы получаете от сервера, включите counter свойство в наблюдаемый и добавить функцию для уменьшения прилавка свойству
  2. Реструктуризации вы код немного так ViewModel воли создаваться к моменту запроса ajax
  3. Переместить applyBindings называть обратный вызов ajax, чтобы он срабатывал, когда все было загружено

Так что код будет выглядеть следующим образом:

<tr> 
     <td data-bind="text: counter"></td>    
     <td> <input type="button" value="decrement" data-bind="click: decrement"></td> 
    </tr> 

    function AppViewModel() { 
     var self = this; 
     self.records = ko.observableArray([]); 
    } 
    var vm = new AppViewModel(); 

    // load data from server 
    $.getJSON("/data", function(data) { 
     data.forEach(function(item) { 

      // make counter observable 
      item.counter = ko.observable(item.counter); 

      // add function to decrement 
      item.decrement = function() { 
      this.counter(this.counter()-1); 
      } 

     }) 

     // load array into viewmodel 
     vm.records(data); 

     // apply bindings when all obervables have been declared 
     ko.applyBindings(vm); 
    }) 

Регистрация демо: Fiddle

+0

Я не знаю, почему, но он не работает при использовании данных с сервера - он вообще не загружает их в таблицу. Я думал, что перемещение ko.applyBindings (vm); ater last parenthasis помог бы и действительно изменил что-то - теперь данные загружены, но я не получаю числа в клетках-счетчиках, но эта странная формула: function c() {if (0 suue

+0

Нет, перемещение 'ko.applyBindings (vm);' это плохая идея, она должна оставаться в обратном вызове ajax. Лучше покажите, что вы получаете от сервера в переменной data. Можете ли вы поместить 'console.dir (data)' before' data.forEach (function (item) {'и увидеть в консоли Chrome, что у вас есть? –

+0

Мой код был упрощен для целей вопроса, у меня есть несколько столбцов в таблице с разными именами, но я использую freeSeats в качестве счетчика здесь (я скопировал первый объект): 0: Object date: "2016-01-09 " декремент:() freeSeats: с() К: Объект Nb: 1 аргументы: NULL звонящего: нулевая длина: 0 имя: "C" прототип: с Symbol (_latestValue):" 3 " __proto__: Объект <функционал> от:" Мадрид " цена:" 30 " до:" Барселона " usernam e: "a" __proto__: Объект Я не знаю, является ли это доступным для чтения, я могу разместить содержимое данных, если вы хотите. В любом случае, данные кажутся прекрасными и загружаются, прежде чем я добавлю этот скрипт. – suue

0

Я предпочитаю, чтобы инициализировать и связать мой ViewModel сразу же, но согласен с другим плакатом, что вам нужен наблюдаемым.

Вот решение, которое продолжает создавать и связывать вашу модель просмотра сразу, как в вашем исходном примере, но вместо массива необработанных записей, которые вы получаете обратно, они преобразуют их в свои небольшие объекты модели, которые имеют наблюдаемый для счетчика и функцию приращения, которая также может быть связана с данными. Это отменит загрузку ваших данных из жизни viewmodel, поэтому, если вы хотите добавить кнопку для загрузки свежих данных, чтобы переписать ее или что-то в этом роде, это просто еще один вызов getData().

<!-- ... --> 
    <tbody data-bind="foreach: records"> 
     <tr> 
      <td data-bind="text: counter"></td>    
      <td> <input type="button" value="increment" data-bind="click: increment" ></td> 
     </tr> 
    </tbody> 
<!-- ... --> 

<script> 
function AppViewModel() { 
    var self = this; 
    self.records = ko.observableArray([]); 

    self.getData = function(){ /* ... */ }; 

    self.getFakeData = function(){ 
     var data = [{ counter: 1 }, { counter: 2}, { counter: 3 }]; 
     var freshData = data.map(function(record){ 
      return new AppRecord(record); 
     }); 
     self.records(freshData);  
    }; 
} 

function AppRecord(rawRecord) { 
    var self = this; 
    self.counter = ko.observable(rawRecord.counter); 
    self.increment = function(){ 
     self.counter(self.counter() + 1); 
    }; 
} 

var vm = new AppViewModel(); 
vm.getFakeData(); // replace with getData() 
ko.applyBindings(vm); 
</script> 

Fiddle с getFakeData с данными выборки: https://jsfiddle.net/4hxyarLa/1/

Если вы собираетесь иметь много строк и обеспокоены примыкают памяти, можно поставить функцию приращения в способе-прототипе для AppRecord и доступ к записи через параметр функции, или вы можете добавить эту функцию в AppViewModel и привязать к $ parent.increment, чтобы вызвать ее и получить доступ к записи через параметр, переданный этой функции, чтобы увеличить его свойство счетчика.

Смежные вопросы