如何在observableArray中订阅observable

时间:2012-12-20 21:28:31

标签: javascript knockout.js

我正在使用KnockoutJS并尝试订阅位于observable的{​​{1}}中的observableArray。所以我的viewModel看起来像这样......

observableArray

从映射插件中填充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); }); } observableArray看起来像这样......

movies

我正在尝试设置订阅UserMovies.Rating但是,从我上面的viewModel获取错误消息

  

TypeError:self.movi​​es.UserMovies未定义

如果从映射插件中填充[{ 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 }] }] ,我将如何设置订阅?

3 个答案:

答案 0 :(得分:7)

Knockout不提供了解数组中哪些项更改的粒度,只是某些内容已更改。每次添加或删除项目时,您都需要循环遍历数组。

foreach绑定(通过ko.utils.compareArrays)实际上计算了将一个数组转换为另一个数组的最小操作数,因此不需要重新创建DOM元素。

使用ko.utils.compareArrays,我能够创建一个在项目级别订阅数组更改的方法。利用这个,我可以编写一个管理订阅的select方法。

http://jsfiddle.net/MizardX/s9M4z/

使用新的select方法,您可以非常简洁地执行此操作:

// 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);
        });
    });
});

按预期处理添加,更新和删除。

答案 1 :(得分:2)

我认为你必须循环播放你的电影并订阅每个人的评级属性:

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

当然,这里的缺点是您还必须订阅阵列本身,以及在阵列中添加新电影的情况,然后手动订阅他们的评级中的更改价值也是如此。

答案 2 :(得分:0)

您可以这种方式订阅您的房产:

   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 || "");
        }
    });

我不确定您订阅对象内部的内容可能做什么或不做什么,但这确实有效。我也不确定每个订阅是否都是唯一的,或者一个评级更改是否会引发所有UserMovies评级订阅。我没有测试过。我只在单个对象而不是对象数组中使用它。