Turn certain observableArray objects properties in

2019-04-30 08:59发布

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条回答
冷血范
2楼-- · 2019-04-30 09:18

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.

查看更多
Juvenile、少年°
3楼-- · 2019-04-30 09:37

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

查看更多
放荡不羁爱自由
4楼-- · 2019-04-30 09:40

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.

查看更多
登录 后发表回答