5

Say I have this array of same-type objects:

var people = [
    { status: 0, name: "name1"},
    { status: 1, name: "name2"}
];

and I want it not only to be observableArray, but also I want to observe ONLY, say, status property of each object.

Imagine that the objects themselves might be added or deleted. The name property of any of those objects is not going to change so I don't really need to observe the name but the status of every object might get changed, thus it'd be cool to make it observable.

Is it possible to map it with knockout utilities with some cool hack syntax or do I have to either iterate through every object and map its status property into observable or have the whole array and its objects properties observable?

3 Answers 3

5

You can use ko.mapping.fromJS

var vm = ko.mapping.fromJS(people,{
    create: function(options){    
        return {
            status : ko.observable(options.data.status), // observable
            name: options.data.name, // non observable
        }
    }
});

Now vm is an observableArray that contains objects in which status is an obsevable and name is a regular property.

See fiddle

@Patryk :

You could do that, if you have many properties and you want to convert only one into observable.

var o = ko.mapping.fromJS(people,{create: function(options){
    // clone item
    var item = ko.utils.extend(options.data, {});
    // replace status property by an observable 
    item.status = ko.observable(options.data.status);
    return item;
}});

See updated fiddle

You could also use observe with mapping parameter

var mapping = {
    create: function (options) {
        return ko.mapping.fromJS(options.data, {'observe': ["status"]});
    }
};
var o = ko.mapping.fromJS(people, mapping);

See fiddle

I hope it helps.

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

3 Comments

And what if the object has way more properties out of which I want just one to be observable, do I need to explicitly list each property regardless whether observable or not?
Came to something like this but your way looks more professional :D what I am curious about again is a simple thing: is var vm = ko.mapping.fromJS(data, {}); the same as var vm; ko.mapping.fromJS(data, {}, vm);
The first call is for the initial call, and second is for update. Update "means" when you receive "fresh" data from the sever and you need to update an existing viewmodel.
1

I suggest use copy

so you can provide array of the properties you want to not be observables.

var mappingPeople = {
    'copy': ["name"]
};

var mapping = {
    create: function (opts) {
        return ko.mapping.fromJS(opts.data, mappingPeople);
    }
};
var PeopleArr = ko.mapping.fromJS(people, mapping);

here is Working Demo

Update

In case you need to mark one property as observable and the rest 'll be normal properties then i suggest to use observe.

here is an update to my Example using observe

3 Comments

That still makes me need to list all the properties that I do not want to be observables, which are the majority. My goal was to name only those that I want to observe. I did it in a manner that Damien suggested, not exactly that clear and knockout-like, but it worked.
@patryk in that case you need to use 'observe' knockoutjs.com/documentation/…
Observe was my first shot, unfortunately I couldn't apply that to an array. Anyway, comparing the two approaches from Damien his answer, which is more efficient when it comes to situation that the object contains many properties?
0

I know this question is old, but I faced the same problem and found a simple solution without using any plugins.

Let's say you do a get request, and get returned an array of posts. For each entry, you have a property called "Favorited", which is a boolean indicating if the post is favorited by the user or not, and you want to make this property observable so you can work in some function that change its state.

You could do the following:

function ViewModel() {
  var self = this;
  self.posts = ko.observableArray([]);

  $.getJSON("/api/getPosts", function(data) {
   ko.utils.arrayForEach(data, function(post) {
    post.Favorited = ko.observable(post.Favorited)
   });
   self.posts(data)
  });
}

This way you turn the favorited property an observable with its value, and you can turn any property observable doing the same thing inside the arrayForEach method.

Comments

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.