I need to edit an array of integers in a web application, using Javascript and Knockout.js. This array will be bound to text boxes, and whenever the value of any text box is changed, the array is updated. And when it gets updated, the sum of the elements is calculated.
This is my first try: http://jsfiddle.net/ZLs2A/0/. Its not working (the sum value is not update when typing a new value for any element). That's when I realized observableArray will only trigger the sum function after inserting or removing items.
<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());
My next attempt was to make every element in the numbers array an observable (http://jsfiddle.net/ZLs2A/1/). It did not work again.
self.numbers = ko.observableArray([
ko.observable(1),
ko.observable(2),
ko.observable(3)
]);
My last try was creating a new class (ArrayItem) to hold the value of the element inside a observable property. This time it worked! (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());
However, I didn't like to have to create this new class ArrayItem. Is there any way to get rid of it, making the example work just having a observableArray of observable elements (like my second attempt)?
You should look at defining the object structure for each element of your array and then add elements of that type to your observable array. Once this is done, you will be able to do something like item. productQuantity(20) and the UI will update itself immediately. EDIT Added the function provided by the OP :).
Description. The KnockoutJS Observable sort() method sorts all items in the array. By default, items are sorted in an ascending order. For sorting an array in a descending order, use reverse() method on sorted array.
It can be like this. var model = { "xId": ko. observable(0), "xName": ko. observable(null), "Type": ko.
shift() — Removes the first value from the array and returns it. reverse() — Reverses the order of the array and returns the observableArray (not the underlying array). sort() — Sorts the array contents and returns the observableArray .
Knockout will not track the value, but as a workaround you can use event keypress or change and update values yourself. See fiddle: 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());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With