11

I have following JavaScript array,

[{"unitPrice": 2499,"currency":"$","productId":1,"retailerId":1,"productName":"XX ","formattedPrice":"$ 2,499","productImage":"Images/2012_08_12_00_45_39_4539.jpg","productQuantity":"9","totalPrice":19992},
{"unitPrice": 4999,"currency":"$","productId":2,"retailerId":1,"productName":"XX","formattedPrice":"$ 4,999","productImage":"Images/2012_08_12_00_46_45_4645.jpg","productQuantity":2,"totalPrice":9998},
{"unitPrice":4555,"currency":"$","productId":1,"retailerId":1,"productName":"XXXXX","formattedPrice":"$ 4,555","productImage":"Images/2013_02_12_10_57_49_5749_9868.png","productQuantity":3,"totalPrice":13665}] 

here is the relevent html,

<table>
<tbody data-bind="foreach: $root">
                    <tr>
                        <td><img width="45" height="45" alt="" data-bind="attr:{src: productImage}"/></td>
                        <td><span data-bind="html: productName"></span></td>
                        <td><span data-bind="html: formattedPrice"></span></td>
                        <td><input type="number" class="quantity" data-bind="value: productQuantity, attr:{'data-id': productId }"  /></td>
                        <td><span data-bind="html: totalPrice"></span></td>
                    </tr>
                </tbody>
</table>

Then I have created observable array as,

observableItems = ko.observableArray(items);
ko.applyBindings(observableItems);

Now I was able to get an specfic element using,

       var obj = ko.utils.arrayFirst(list(), function (item) {
            return item.productId === id;
        });

However when I change,

item.productQuantity = 20;

But UI is not updating. Tried also,

item.productQuantity(item.productQuantity)

But getting error productQuantity is not a function

2 Answers 2

18

The above behavior is because only the array is an observable and not the individual elements within the array or the properties of each element.

When you do item.productQuantity = 20;, this will update the property but since it is not an observable, the UI does not get updated.

Similary, item.productQuantity(20) gives you an error because productQuantity is not an observable.

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 :). This function will convert each property of the elements in an array to observables.

function convertToObservable(list) 
{ 
    var newList = []; 
    $.each(list, function (i, obj) {
        var newObj = {}; 
        Object.keys(obj).forEach(function (key) { 
            newObj[key] = ko.observable(obj[key]); 
        }); 
        newList.push(newObj); 
    }); 
    return newList; 
}

END EDIT

If you are unable to change that piece of code, you can also do something like observableItems.valueHasMutated(). However, this is not a good thing to do as it signals to KO and your UI that the whole array has changed and the UI will render the whole array based on the bindings.

Sign up to request clarification or add additional context in comments.

6 Comments

Got it by adding this function, function convertToObservable(list) { var newList = []; $.each(list, function (i, obj) { var newObj = {}; Object.keys(obj).forEach(function (key) { newObj[key] = ko.observable(obj[key]); }); newList.push(newObj); }); return newList; }
Please put this inside answer.
Sure thing, where did you get the script from thought ?
ok but could you use this function to keep the observable array as an observable array as well?
I think this is the answer to my question? ko.observableArray(convertToObservable(myArray)
|
12

You can easily use ko.mapping plugin to convert object to become observable: http://knockoutjs.com/documentation/plugins-mapping.html

Convert regular JS entity to observable entity:

var viewModel = ko.mapping.fromJS(data);

Convert observable object to regular JS object:

var unmapped = ko.mapping.toJS(viewModel);

2 Comments

ok, but if the observable array is an array of many objects, how would you update an individual property of one object in the array using this method?
You need to know exactly what object is going to be updated in your array, hence you convert that particular object to observable. That's good for performance wise as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.