1

我正在使用 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该电影的更新属性。

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

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属性的“键”映射。http://jsfiddle.net/cmBd9/3/

4

2 回答 2

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;
              }
            });
        }
    });
};

一定要检查映射插件。我唯一担心的是文档显示了如何最初从 JSON 映射对象,以及以后如何从 JSON 更新整个对象。

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

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

于 2012-12-18T04:39:11.757 回答
0

我能够使用映射选项使其与映射插件一起使用。我将密钥设置为UserMovies每个的 ID,UserMovie所以当fromJS()被调用时,它会查看每个的 IDUserMovie来判断是更新还是添加新的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);
                }
            }
        });
    };
}
于 2012-12-19T19:59:21.753 回答