【问题标题】:Updating a property of an item in an observableArray and persisting to template更新 observableArray 中项目的属性并持续到模板
【发布时间】:2012-12-17 20:18:47
【问题描述】:

我正在使用 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 属性创建“键”映射。 http://jsfiddle.net/cmBd9/3/

【问题讨论】:

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


    【解决方案1】:

    您自己正确地注意到,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 方法的服务调用返回整个电影对象,以便您更紧密地遵循映射插件所支持的模型。

    【讨论】:

    • 我考虑过更换控制器以返回整部电影。我可能只需要走那条路。我真的很喜欢使用映射插件的想法,但就像你说的,我找不到更新属性的方法。
    • 我使用映射插件创建了一个小提琴,但在让它工作时遇到了问题。 jsfiddle.net/cmBd9/1
    • 看起来支持部分更新,但在使用数组中的项目时必须小心。请参阅 stackoverflow.com/questions/10213104/… 和 stackoverflow.com/questions/11370052/…。这能满足你的需要吗?
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-10
      • 2015-08-04
      • 2012-02-24
      • 2015-07-22
      • 2017-10-01
      • 1970-01-01
      相关资源
      最近更新 更多