最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to subscribe to observable in observableArray - Stack Overflow

programmeradmin3浏览0评论

I'm using KnockoutJS and trying to subscribe to an observable that is in an observableArray that is in an observableArray. So my viewModel looks like this...

function viewModel() {
    // private properties
    var self = this;

    // public properties
    self.movies = ko.mapping.fromJS([]);

    // subscriptions
    self.movies.UserMovies.Rating.subscribe(function(newValue) {
        console.log(newValue);
    });
}

The movies observableArray would look like this once populated from the mapping plugin...

[{
    Id: 1,
    Title: 'Movie1',
    Year: 2010,
    UserMovies: [{ Id: 11, Rating: 3.5, IsWatched: true }]
},{
    Id: 2,
    Title: 'Movie2',
    Year: 2010,
    UserMovies: [{ Id: 4, Rating: 4, IsWatched: true }]
}]

I'm trying to set up a subscription to UserMovies.Rating but, from my above viewModel getting the error message

TypeError: self.movies.UserMovies is undefined

How would I got about setting up a subscription to UserMovies.Rating when it is populated from the mapping plugin?

I'm using KnockoutJS and trying to subscribe to an observable that is in an observableArray that is in an observableArray. So my viewModel looks like this...

function viewModel() {
    // private properties
    var self = this;

    // public properties
    self.movies = ko.mapping.fromJS([]);

    // subscriptions
    self.movies.UserMovies.Rating.subscribe(function(newValue) {
        console.log(newValue);
    });
}

The movies observableArray would look like this once populated from the mapping plugin...

[{
    Id: 1,
    Title: 'Movie1',
    Year: 2010,
    UserMovies: [{ Id: 11, Rating: 3.5, IsWatched: true }]
},{
    Id: 2,
    Title: 'Movie2',
    Year: 2010,
    UserMovies: [{ Id: 4, Rating: 4, IsWatched: true }]
}]

I'm trying to set up a subscription to UserMovies.Rating but, from my above viewModel getting the error message

TypeError: self.movies.UserMovies is undefined

How would I got about setting up a subscription to UserMovies.Rating when it is populated from the mapping plugin?

Share Improve this question asked Dec 20, 2012 at 21:28 bflemi3bflemi3 6,79021 gold badges95 silver badges158 bronze badges 1
  • You can use the latest version of this plugin if you want in depth subscription to arrays: github./ZiadJ/knockoutjs-reactor – Ziad Commented Jun 6, 2013 at 9:10
Add a ment  | 

3 Answers 3

Reset to default 8

Knockout does not provide the granularity for knowing which items changed in an array, just that something changed. You will need to loop trough the array each time an item is added or removed.

The foreach binding (via ko.utils.pareArrays) actually calculates the minimum number of operations to transform one array into another one, so that DOM-elements does not need to be recreated.

Using ko.utils.pareArrays, I was able to create a method that subscribes to array changes at an item level. Leveraging this, I could write a select method that manages the subscriptions.

http://jsfiddle/MizardX/s9M4z/

With the new select method, you could do this pretty concisely:

// Subscribe to items added to the array. The returned 'subscription' will be
// disposed of, when the item is later removed.
viewModel.movies.select(function (movie) {

    // Return the subscription. Same as above.
    return movie.UserMovies.select(function (userMovie) {

        // Subscribe to a non-array. The callback will receive the updated value,
        // instead of the an added item.
        return userMovie.Rating.select(function (rating) {

            // Executed each time a rating is updated.
            console.log(movie.Id(), userMovie.Id(), rating);
        });
    });
});

It handles additions, updates, and deletions as expected.

I think you'll have to loop through your movies and subscribe to each one's rating property:

$.each(self.movies(), function(i, movie) { 
     movie.Rating.subscribe(function(newRatingValue){  /* ... */ }) 
});

Of course the donwside here is that you'll also have to subscribe to the array itself, for situations in which you add new movies to the array, and then manually subscribe to changes in their rating value as well.

You can kind of subscribe to your properties in this fashion:

   var UserMovies = function (data) {
        this.Id = ko.observable();
        this.Rating = ko.observable();
        this.IsWatched = ko.observable();
        this.update(data);
    }

    ko.utils.extend(UserMovies.prototype, {
        update: function (data) {
            this.Id(data.Id || "");
            this.Rating(data.Rating || "");
            this.Rating.subscribe(function (newValue) {
                console.log(newValue);
            });
            this.IsWatched(data.IsWatched || "");
        }
    });

I'm not sure what you might be able to do or not do from subscribing to things inside of your object, but this does work. I'm also not sure if each subscription will be unique, or if one Rating change will set off all UserMovies ratings subscriptions. I have not tested that. I've only used this in single objects and not arrays of objects.

发布评论

评论列表(0)

  1. 暂无评论