javascript 如何订阅 observableArray 中的 observable

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13980753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 20:23:03  来源:igfitidea点击:

How to subscribe to observable in observableArray

javascriptknockout.js

提问by bflemi3

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

我使用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);
    });
}

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

moviesobservableArray应该是这样的,一旦从映射插件填充...

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

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

TypeError: self.movies.UserMovies is undefined

类型错误:self.movi​​es.UserMovies 未定义

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

UserMovies.Rating当从映射插件填充时,我将如何设置订阅?

回答by Markus Jarderot

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

Knockout 不提供知道数组中哪些项目发生变化的粒度,只是知道某些内容发生变化。每次添加或删除项目时,您都需要遍历数组。

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

foreach(通过结合ko.utils.compareArrays)实际上计算操作的最小数量,以一个阵列变换为另一个,使得不需要DOM元素重新创建。

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

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

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

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

With the new selectmethod, you could do this pretty concisely:

使用新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);
        });
    });
});

It handles additions, updates, and deletions as expected.

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

回答by Adam Rackis

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 theirrating value as well.

当然,这里的缺点是您还必须订阅数组本身,在这种情况下,您将新电影添加到数组中,然后手动订阅评级值的更改。

回答by Barry Franklin

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.

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