Javascript 更新ObservalArray中项目的属性并持久化到模板
我正在使用KnockoutJS 我的viewModel中有一系列电影。当用户按标题搜索电影时,该数组会更新,因此将推送到数组中的典型json响应如下所示Javascript 更新ObservalArray中项目的属性并持久化到模板,javascript,knockout.js,knockout-mapping-plugin,Javascript,Knockout.js,Knockout Mapping Plugin,我正在使用KnockoutJS 我的viewModel中有一系列电影。当用户按标题搜索电影时,该数组会更新,因此将推送到数组中的典型json响应如下所示 {data : [{ Id: 12345, Title: 'Movie1', Year: 2010, Character: [{ Name: 'Character1', Person: { Id: 1, Name: 'Person1' } },{ Name:
{data : [{
Id: 12345,
Title: 'Movie1',
Year: 2010,
Character: [{
Name: 'Character1',
Person: { Id: 1, Name: 'Person1' }
},{
Name: 'Character2',
Person: { Id: 2, Name: 'Person2' }
}],
UserMovies: [{
Id: 8
IsWatched: false,
Rating: 3.5,
UserId: 'e1e9c075-1ded-4e7d-8d30-d5d1fbd47103'
}]
}]}
每个电影的UserMovies属性表示特定于该用户的信息,如他们的个人评级或他们是否观看过电影等
我让用户能够将电影添加到他们在数据库中的收藏中。当他们将电影添加到集合中时,会返回一个json响应,该响应具有该电影的更新UserMovies属性
我正在尝试只更新该属性,然后将其保留到敲除模板。这是我当前的视图模型
function viewModel() {
// private properties
var self = this;
// public properties
self.movies = ko.observableArray([]);
self.searchValue = ko.observable();
// public operations
self.search = function () {
self.isLoading(true);
$.getJSON(arguments[0].action, { name: this.searchValue() }, function (data) {
self.movies(data);
});
};
self.add = function (movie) {
$.ajax({
type: 'POST',
url: arguments[1].currentTarget.attributes[1].value,
data: JSON.stringify({ movie: movie }),
contentType: 'application/json',
dataType: 'json',
success: function (data) {
// how to just update UserMovies property and persist to template for the given movie?
}
});
};
}
ko.applyBindings(new viewModel());
我不确定如何更新属性,但就将数据持久化到淘汰模板而言,我认为这是因为每部电影的UserMovies属性本身不是可观察的,因此如果它被更新,模板中的任何内容都不会自动更改
我一直在读关于映射插件的书,它可以使每个属性都是可观察的。这可能会解决我的持久性问题,但我仍然不确定如何仅更新UserMovies属性,无论它是在observableArray中还是通过映射插件
更新
我已经使用映射插件创建了一个fiddle。如果我返回整个电影,而不仅仅是UserMovies属性,那么更新数组中的一个项目就会容易得多。但是,我在让它工作时遇到了一些问题,我正在努力找出如何针对UserMovies属性创建“key”的映射 正如您自己正确地注意到的,UserMovies属性是不可观察的,这意味着即使您更新它,UI中也不会发生任何事情。尽管如此,以下是如何更新不可见的UserMovies:
self.add = function (movie) {
$.ajax({
type: 'POST',
url: arguments[1].currentTarget.attributes[1].value,
data: JSON.stringify({ movie: movie }),
contentType: 'application/json',
dataType: 'json',
success: function (data) {
ko.utils.arrayForEach(self.movies(), function(m) {
if (m.Id == movie.Id) {
m.UserMovies = data;
}
});
}
});
};
一定要看看这本书。我唯一关心的是文档显示了如何从JSON映射一个对象,以及以后如何从JSON更新整个对象
然而,它似乎没有提到任何关于从JSON映射一个对象以及随后从JSON只更新该对象的一部分的内容,所以我不确定这是否有效
如果您遇到问题,可以尝试让add方法的服务调用返回整个movie对象,以便您更密切地遵循映射插件支持的模型。我能够使用映射选项让它与映射插件一起工作。我将UserMovies的键设置为每个UserMovie的Id,因此当调用fromJS时,它将查看每个UserMovie的Id来判断是更新还是添加新的UserMovie 这是我的更新代码
function viewModel() {
// private properties
var self = this;
var mapping = {
'UserMovies': {
key: function (data) {
return ko.utils.unwrapObservable(data.Id);
}
}
};
// public properties
self.movies = ko.mapping.fromJS([]);
self.searchValue = ko.observable();
// public operations
self.search = function () {
self.isLoading(true);
$.getJSON(arguments[0].action, { name: this.searchValue() }, function (data) {
ko.mapping.fromJS(data, {}, self.movies);
});
};
self.add = function (movie) {
$.ajax({
type: 'POST',
url: arguments[1].currentTarget.attributes[1].value,
data: ko.toJSON({ movie: movie }),
contentType: 'application/json',
dataType: 'json',
success: function (data) {
if(data.success) {
ko.mapping.fromJS(data.movie, mapping, movie);
}
}
});
};
}
我考虑过更换控制器以返回整个电影。我可能得走那条路了。我真的很喜欢使用映射插件的想法,但正如你所说,我找不到更新属性的方法。我使用映射插件创建了一个fiddle,但在使用它时遇到了问题。看起来支持部分更新,但在处理数组中的项时必须小心。见和。这能满足你的需要吗?