Javascript 更新ObservalArray中项目的属性并持久化到模板

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:

我正在使用KnockoutJS

我的viewModel中有一系列电影。当用户按标题搜索电影时,该数组会更新,因此将推送到数组中的典型json响应如下所示

{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,但在使用它时遇到了问题。看起来支持部分更新,但在处理数组中的项时必须小心。见和。这能满足你的需要吗?