2013-05-02 11 views
5

Potrzebuję edytować tablicę liczb całkowitych w aplikacji internetowej, używając Javascript i Knockout.js. Tablica ta będzie powiązana z polami tekstowymi, a ilekroć zmieni się wartość dowolnego pola tekstowego, tablica zostanie zaktualizowana. A gdy zostanie zaktualizowany, obliczana jest suma elementów. To jest moja pierwsza próba: http://jsfiddle.net/ZLs2A/0/. Nie działa (wartość sumy nie jest aktualizowana podczas wpisywania nowej wartości dla dowolnego elementu). Wtedy uświadomiłem sobie, że obserservableArray wywoła funkcję sumującą dopiero po wstawieniu lub usunięciu elementów.Zmiany śledzenia - obserwowalny element w obserservArray

<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()); 

Moja następna próba była, aby każdy element tablicy liczb zauważalny (http://jsfiddle.net/ZLs2A/1/). To już nie działało.

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

Moja ostatnia próba polegała na utworzeniu nowej klasy (ArrayItem) w celu zachowania wartości elementu wewnątrz obserwowalnej właściwości. Tym razem zadziałało! (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()); 

Jednak nie lubią mieć do stworzenia tej nowej klasy ArrayItem. Czy istnieje sposób, aby się go pozbyć, dzięki czemu przykład działa tylko o obserwowalne Array z obserwowalnych elementów (jak moja druga próba)?

+2

Autor KO odpowiedział [ten (? Możliwy duplikat) Pytanie] (http://stackoverflow.com/questions/9510539/knockout-js-how-to-correctly-bind-an -observablearray), w zasadzie w podobny sposób do twojej ostatecznej wersji z konstruktorem 'ArrayItem' (po prostu wstawia tę funkcję). Odpowiedź jest roczna, więc coś mogło się zmienić w międzyczasie ... Jeśli tak się nie stało, wydaje się, że już odpowiedziałeś na własne pytanie. – Jeroen

+0

Warto wspomnieć o integracji Breeze.js z Knockout.js, która dodaje między innymi śledzenie zmian. http://www.breezejs.com/ –

Odpowiedz

2

Knockout nie śledzi wartości, ale jako obejście można użyć klawisza zdarzenia lub zmienić i zaktualizować wartości samodzielnie. Zobacz skrzypce: 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

Chociaż wydaje się, że działa z IE11, suma w przykładzie jsfiddle nie aktualizuje się na zmiany wartości w polu tekstowym w przeglądarce Firefox 45.0.1 – Stefan

Powiązane problemy