3

We have an observableArray in Knockout which include several JSON objects. Under each JSON object we have an nested array which needs to be observable.

Knockout is not able to observe arrays nested in each JSON object, in the observableArray.

Is it possible to map an array which is already nested in an observableArray?

Here is an example of one JSON object in the observableArray.

Note: We need to make the "attributeValues" array observable.

{
    "attribute": {
        "id": 6,
        "name": "Some attribute name",
        "typeID": 5
    },
    "type": {
        "id": 5,
        "typeName": "list"
    },
    "attributeValues": [{
        "id": 10,
        "attributeID": 6,
        "value": "Some attribute value",
        "chosen": false
    }, {
        "id": 11,
        "attributeID": 6,
        "value": "Another attribute value",
        "chosen": false
    }, {
        "id": 12,
        "attributeID": 6,
        "value": "Third attribute value",
        "chosen": false
    }]
}

Here is the code we're using now:

$.ajax({
    type: 'GET',
    url: '/JsonService',
    success: function (data) {
        avm.attributes(data.allAttributes);
    },
    dataType: 'json',
    traditional: true
});

function attributeViewModel() {
    var self = this;

    self.attributes = ko.observableArray([]);
}

var avm = new attributeViewModel();
ko.applyBindings(avm);

1 Answer 1

5

One solution would be to define one more constructor function to wrap each item of the attributes array. In this function, you can then define the attributeValues array as observable as illustrated in the following example:

function AttributeValueViewModel (data) {
    var self = this;
    self.attribute = ko.observable(data.attribute);
    self.type = ko.observable(data.type);
    self.attributeValues = ko.observableArray(data.attributeValues);
}

function attributeViewModel() {
    var self = this;
    self.attributes = ko.observableArray([]);
    self.addList = function (list) {
        ko.utils.arrayForEach(list, function(item) {
            self.attributes.push(new AttributeValueViewModel(item));
        });
    };
}

var avm = new attributeViewModel();
ko.applyBindings(avm);
$.getJSON('url', function (list) { avm.addList(list); });
Sign up to request clarification or add additional context in comments.

6 Comments

It's not working. After the addList() arrayForEach loop I put: console.log(self.attributes()); and got: [{},{},{},{},{},{}]. I also verified the data from the parameter 'item' and got correct data, but after the loop it doesn't display any data.
The following fiddle contains a working example: jsfiddle.net/ELMkS/2. You can see that the array items are not empty.
This is so weird. Here is my code/output: pastebin.com/NNYj1bbW - The only difference is that you call avm.addList() below ko.applyBindings(avm) but I call it in "success" in the AJAX function. I even tried to move the AJAX below ko.applyBindings(avm) but no luck.
But doing like that, you removed the observable in the nested array (the goal of your question!!). The problem lies in the way you get the JSON representation of the object. When using objects with observables, you cannot use anymore JSON.stringify but ko.toJSON (a special version dealing with observable). That's why your array seemed empty.
Common mistake in KO: when using observable in binding expression, they must be called using a function call. Here is a working fiddle with your example: jsfiddle.net/ELMkS/3
|

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.