Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observable objects inside observableArray do not automatically update [duplicate]

I have been looking into an Knockout for dynamic data-bind and I have a situation where I need an observable array to contain multiple observable objects.

This is my code:

<ul data-bind="foreach: { data: categories, as: 'category' }">
    <li>
        <ul data-bind="foreach: { data: items, as: 'item' }">
            <li>
                <span data-bind="text: category.name"></span>:
                <span data-bind="text: item"></span>
                <input type="text" data-bind="value: item"/>
            </li>
        </ul>
    </li>
</ul>

$(document).ready(function () {
            ko.applyBindings(viewModel);
        });

        var viewModel = {
            categories: ko.observableArray([
                { name: 'Fruit', items: [ko.observable('Apple'), ko.observable('Orange'), ko.observable('Banana')] },
                { name: 'Vegetables', items: [ko.observable('Celery'), ko.observable('Corn'), ko.observable('Spinach')] }
            ])
        };

When working with oject observables usually I could modify a value of an input text box and that value is set to the entire page where that property was used to be displayed.

In my current example I tried to do the same with my input box , but after I modified the values in the text box the span did not to the curent value.

How can I make the observable objects inside the observableArray behave as they would have if they were stand alone observable objects?

like image 673
aleczandru Avatar asked Nov 12 '22 05:11

aleczandru


1 Answers

when i encounter these issues, i like to break them down into sub vms, which allow me better control over what is happening at each level of context that im in. for your issues above, i would do something like this:

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

    self.item = ko.observable(data);
}

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

    self.name = ko.observable(data.name);
    self.items = ko.observableArray();

    var items = ko.utils.arrayMap(data.items, function (item) {
        return new produceVM(item);
    });

    self.items(items);
}

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

    self.categories = ko.observableArray();

    var categories = ko.utils.arrayMap(data, function (category) {
       return new categoryVM(category); 
    });

    self.categories(categories);
}

var data = [
    { name: 'Fruit', items: [ 'Apple', 'Orange', 'Banana' ] },
    { name: 'Vegetables', items: ['Celery', 'Corn', 'Spinach' ]}
];

ko.applyBindings(new viewModel(data));

I believe the ko mapping plugin achieves something similar to this without having to write all of the above code. you could pass it the data model and it would construct the observables for each item.

like image 87
Kevin Nacios Avatar answered Nov 14 '22 22:11

Kevin Nacios