2013-05-02 3 views
5

Мне нужно отредактировать массив целых чисел в веб-приложении, используя Javascript и Knockout.js. Этот массив будет привязан к текстовым полям, и всякий раз, когда значение любого текстового поля будет изменено, массив будет обновлен. И когда он обновляется, вычисляется сумма элементов.Отслеживание изменений - наблюдаемый элемент в наблюдаемом массиве

Это моя первая попытка: http://jsfiddle.net/ZLs2A/0/. Его не работает (значение суммы не обновляется при вводе нового значения для любого элемента). Вот когда я понял, что наблюдаемыйArray будет запускать функцию sum только после вставки или удаления элементов.

<h4>Numbers</h4> 
<button data-bind="click: add">Add</button> 
<ul data-bind="foreach: numbers"> 
    <li> 
     <input data-bind="value: $data"></input> 
    </li> 
</ul> 
<span data-bind="text: sum"></span> 

function MyViewModel() { 
    var self = this; 

    self.numbers = ko.observableArray([ 
     1, 
     2, 
     3 
    ]); 

    self.sum = ko.computed(function() { 
     var items = self.numbers(); 
     var total = 0; 
     for (var i = 0; i < items.length; i++) { 
      total += parseInt(items[i]); 
     } 
     return total; 
    }); 

    self.add = function() { 
     var lastIndex = self.numbers().length - 1; 
     var lastValue = self.numbers()[lastIndex]; 
     self.numbers.push(lastValue + 1); 
    } 
} 

ko.applyBindings(new MyViewModel()); 

Моя следующая попытка была сделать каждый элемент в массиве чисел наблюдаемой (http://jsfiddle.net/ZLs2A/1/). Это не сработало.

self.numbers = ko.observableArray([ 
    ko.observable(1), 
    ko.observable(2), 
    ko.observable(3) 
]); 

Моя последняя попытка была создать новый класс (ArrayItem) удерживать значение элемента внутри наблюдаемого свойства. На этот раз это сработало! (http://jsfiddle.net/ZLs2A/3/)

<h4>Numbers</h4> 
<button data-bind="click: add">Add</button> 
<ul data-bind="foreach: numbers"> 
    <li> 
     <input data-bind="value: value"></input> 
    </li> 
</ul> 
<span data-bind="text: sum"></span> 

function MyViewModel() { 
    var self = this; 

    self.numbers = ko.observableArray([ 
     new ArrayItem(1), 
     new ArrayItem(2), 
     new ArrayItem(3) 
    ]); 

    self.sum = ko.computed(function() { 
     var items = self.numbers(); 
     var total = 0; 
     for (var i = 0; i < items.length; i++) { 
      total += parseInt(items[i].value()); 
     } 
     return total; 
    }); 

    self.add = function() { 
     var lastIndex = self.numbers().length - 1; 
     var lastItem = self.numbers()[lastIndex]; 
     var newValue = parseInt(lastItem.value()) + 1; 
     self.numbers.push(new ArrayItem(newValue)); 
    } 
} 

function ArrayItem(value){ 
    var self = this; 
    self.value = ko.observable(value); 
} 

ko.applyBindings(new MyViewModel()); 

Однако, я не хотел, чтобы создать этот новый класс ArrayItem. Есть ли способ избавиться от него, заставив пример работать с наблюдаемым массивом наблюдаемых элементов (например, моя вторая попытка)?

+2

Автор KO ответил [это (? Можно дублировать) вопрос] (http://stackoverflow.com/questions/9510539/knockout-js-how-to-correctly-bind-an -observablearray), в основном аналогично вашей окончательной версии с конструктором ArrayItem (он просто встроил эту функцию). Ответ - год, поэтому, возможно, что-то изменилось в среднем ... Если это не так, похоже, вы уже ответили на свой вопрос. – Jeroen

+0

Возможно, стоит упомянуть интеграцию Breeze.js с Knockout.js, которая добавляет отслеживание изменений среди других вещей. http://www.breezejs.com/ –

ответ

2

Нокаут не будет отслеживать значение, но в качестве обходного пути вы можете использовать нажатия клавиш или изменить или обновить значения самостоятельно. См скрипку: http://jsfiddle.net/tkirda/ZLs2A/4/

function MyViewModel() { 
    var self = this; 

    self.numbers = ko.observableArray([ 
     1, 
     2, 
     3 
    ]); 

    self.onChange = function(val, e){ 
     var el = e.srcElement; 
     var newVal = parseInt(el.value); 
     var index = parseInt(el.getAttribute('data-index')); 
     self.numbers()[index] = newVal; 
     self.updateSum(); 
    } 

    self.sum = ko.observable(0); 

    self.updateSum = function() { 
     var items = self.numbers(); 
     var total = 0; 
     for (var i = 0; i < items.length; i++) { 
      total += parseInt(items[i]); 
     } 
     self.sum(total); 
    }; 

    self.updateSum(); 

    self.add = function() { 
     var lastIndex = self.numbers().length - 1; 
     var lastValue = self.numbers()[lastIndex]; 
     self.numbers.push(lastValue + 1); 
    } 
} 

ko.applyBindings(new MyViewModel()); 
+0

Хотя это, похоже, работает с IE11, сумма в примере jsfiddle не обновляется при изменении значений в текстовом поле в Firefox 45.0.1 – Stefan

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