Search code examples
knockout.jsknockout-3.0knockout-3.2

Create observable object properties inside an array in knockout.js


Knockout.js docs says about observableArray

Simply putting an object into an observableArray doesn’t make all of that object’s properties themselves observable. Of course, you can make those properties observable if you wish, but that’s an independent choice.

But it doesn't specify how to make a property observable.

I have an array of users and I would like to make the property name observable to be able to change it from another viewmodel under some action.

This is what I've tried without success:

Reproduction online

var shouter = new ko.subscribable();

function usersViewModel() {
    var myData = [array of objects];
    var self = this;
    self.selectedRow = ko.observable();
    self.items = ko.observableArray(myData);

    self.selectedRow.subscribe(function (newValue) {
        console.log(newValue);
        shouter.notifySubscribers(newValue, "selectedRow");
    });

}

function departmentViewModel() {
    var self = this;
    self.row = ko.observable();

    //getting info from another view model
    shouter.subscribe(function (user) {
        self.row(user);
        console.log(self.row());

        self.row().name = ko.observable('Testing!!!');
    }, this, "selectedRow");

}

var MasterViewModel = function () {
    this.users = new usersViewModel();
    this.department = new departmentViewModel();
}

var mm = new MasterViewModel();
ko.applyBindings(mm);

How could I do it?


Solution

  • You should make a User class that has name as an observable property.

    function User(userData) {
        userData = userData || {};
        this.id = userData.id;
        this.name = ko.observable(userData.name);
        this.status = userData.status;
    }
    
    function UsersViewModel() {    
        var myData = [{
            id: "001",
            name: "Jhon",
            status: "Single"
        }, {
            id: "002",
            name: "Mike",
            status: "Married"
        }, {
            id: "003",
            name: "Marrie",
            status: "Complicated"
        }];
    
        self.users = ko.observableArray(myData.map(function(userData) {
            return new User(userData);
        });
    }
    

    If for some reason you want to avoid creating a User class then you'll need to transform the name property into an observable some other way. Like so...

    myData.forEach(function (data) {
        data.name = ko.observable(data.name);
    });
    self.users = ko.observableArray(myData);