【问题标题】:How to subscribe to observable in observableArray如何订阅 observableArray 中的 observable
【发布时间】:2012-12-20 21:28:31
【问题描述】:

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

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

movies observableArray 从映射插件中填充后看起来像这样...

[{
    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 }]
}]

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

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

如果从映射插件填充UserMovies.Rating,我该如何设置订阅?

【问题讨论】:

标签: javascript knockout.js


【解决方案1】:

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

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

【讨论】:

  • 这是一个很好的答案。谢谢马库斯 :)
  • @bflemi3 我对以前的版本不满意,因为它无法处理删除。这个更健壮。
【解决方案2】:

我认为你必须遍历你的电影并订阅每个电影的评级属性:

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

当然,这里的缺点是您还必须订阅数组本身,以应对将新电影添加到数组的情况,然后手动订阅 他们的 评级变化价值也是如此。

【讨论】:

    【解决方案3】:

    您可以通过这种方式订阅您的属性:

       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 评级订阅。我没有测试过。我只在单个对象而不是对象数组中使用它。

    【讨论】:

      猜你喜欢
      • 2013-04-25
      • 1970-01-01
      • 2020-10-01
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      • 2019-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多