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
How to subscribe to observable in observableArray
提问by bflemi3
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...
我使用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 movies
observableArray would look like this once populated from the mapping plugin...
该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 }]
}]
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.movies.UserMovies 未定义
How would I got about setting up a subscription to UserMovies.Rating
when 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 foreach
binding (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 select
method that manages the subscriptions.
使用ko.utils.compareArrays
,我能够创建一个在项目级别订阅数组更改的方法。利用这一点,我可以编写一个select
管理订阅的方法。
http://jsfiddle.net/MizardX/s9M4z/
http://jsfiddle.net/MizardX/s9M4z/
With the new select
method, 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 评级订阅。我没有测试过。我只在单个对象中使用过它,而不是对象数组。