更新observableArray中项目的属性并持久保存到模板

时间:2012-12-17 20:18:47

标签: javascript knockout.js knockout-mapping-plugin

我正在使用KnockoutJS ......

我的viewModel中有observableArray部电影。当用户按标题搜索电影时,数组会更新,因此推送到数组中的典型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属性。

我正在尝试更新该属性,然后将其保留到淘汰模板中。这是我当前的viewModel ......

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还是通过映射插件。

更新

我使用映射插件创建了一个小提琴。如果我返回整部电影而不仅仅是UserMovies属性,那么更新数组中的项目会更容易。我有一些问题让它工作,我正在努力弄清楚如何为UserMovies属性创建'key'的映射。 http://jsfiddle.net/cmBd9/3/

2 个答案:

答案 0 :(得分:0)

正如您自己正确指出的那样,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;
              }
            });
        }
    });
};

绝对查看mapping plugin。我唯一关心的是文档显示了如何从JSON初始映射对象,以及稍后如何从JSON更新整个对象。

但是,它似乎没有提到任何关于从JSON映射对象以及稍后出现并仅从JSON更新该对象的部分的内容,因此我不确定这是否有效或不。

如果您遇到问题,可以尝试让add方法的服务调用返回整个影片对象,以便您更加密切地关注映射插件所支持的模型。

答案 1 :(得分:0)

我能够使用映射选项使用映射插件。我将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);
                }
            }
        });
    };
}