2
votes

I have a ko.observableArray that when the page gets initialized 1 item is added. I then use a and a data-bind="foreach items" to create a div for each item in the ko.observableArray. I have a button and textbox on the page that when you add text to the input and click the button a new item gets pushed on to the ko.observableArray. This works fine I can add a new items with each button click. The items in the ko.observableArray have a price associated with them and the price changes. I want to update the price while still being able to add new items to the ko.observableArray. The price and item name are also ko.observable.

self.items= ko.observableArray(ko.utils.arrayMap(items, function(item) { return { name: ko.observable(item.name), price: ko.observable(item.price) };

How to I update the underlying item values (price) and not recreate the ko.observable array? Do I have to loop through each item in the ko.observable array? The data is coming from a JSON call. BTW I am new to Knockout.js.

Here is my attempt at a JSFiddle but I could not get it fully working. Adding an item works fine but when I update if I have a different amount of item..like less items the ones not getting updated are destroyed. Anyway around this? I do not want to fetch data that does not have any changes in it.

1
Simple way: don't rebind. Use the same observable array. The mapping plugin has support for updating existing array items: see plugins-mapping and pay attention to the keys/update mappings. (You could of course do the same manually, but avoid creating new observables where possible - it just makes KO grumpy and harder to deal with.)user2864740
OK, I looked at the plugins-mapping and got a little lost as I am new to knockout and wanted to keep it simple. I will give the plugin an in depth read.JTime
Can you create a more complete (though short as possible) example in your question? We can probably help you, even withouth ko-mapping (a good suggestion nonetheless), but it's rather hard to imagine your context.Jeroen
And if, in addition, you can also post that code in a fiddle that shows your scenario, it would be even easier to help.Jeroen
Working on the JS fiddleJTime

1 Answers

1
votes

Do something like this instead

Javascript

var itemObject = function(data){
    var self = this;

    //I recommend using the mapping plugin
    //ko.mapping.fromJS(data, {}, self);

    //If you use the mapping plugin, you don't have to hand bind each property
    this.Id = ko.observable(data.Id);
    .... etc ....
};

var baseViewModel = function(){
    var self = this;

    this.Items = ko.observableArray();

    this.Setup = function(items){
        //using underscore.js to map the items.
        //This turns each item into an "itemObject", which you can 
        //then manipulate and have all changes shown on the screen, even 
        //inside the array.
        self.Items(_.map(items, function(item){
            return new itemObject(item);
        }));
    };
};

$(function(){
  var myApp = new baseViewModel();
  myApp.Setup(items);
  ko.applyBindings(myApp);
});

html

<div data-bind="foreach: Items">
    <div data-bind="text: Id"></div>
    <!-- other binding things here -->
</div>