объединить основную коллекцию с ответом сервера - PullRequest
6 голосов
/ 21 ноября 2011

TL; DR : Если я опрашиваю всю коллекцию моделей с сервера, как я могу объединить измененные атрибуты в каждую модель и добавить / удалить добавленные / удаленные модели из коллекции?

В своем базовом приложении я опрашиваю всю коллекцию моделей. У меня есть Backbone.Collection, который я в основном называю reset каждый раз, когда получаю массив моделей, поэтому:

myCollection.reset(server_response);

Единственная проблема с этим состоит в том, что он избавляется от старых моделей, отчасти устраняя выгоду событий на модели. Это, конечно, цель reset, но я хочу лишь изменить измененные атрибуты моделей и удалить модели, отсутствующие в ответе, и добавить модели, которые были в ответе, но не в коллекции.

По сути, я хочу что-то вроде объединения данных.

Для моделей, которые уже есть в ответе и в коллекции, я думаю, что я могу просто сделать model.set(attributes), и он позаботится о set только о тех, которые действительно изменились, вызывая события change в процессе. , Это здорово.

Но как мне справиться со случаями, когда модели были в ответе, но уже не в коллекции, и наоборот, не в ответе, а в коллекции?

Мое предлагаемое решение

Я не знаю, есть ли у магистрали способ сделать это, и я, может быть, слишком усложняю, поэтому и спрашиваю, но тогда я думал о создании метода в моей коллекции, который получает server_response .

Он получит все атрибуты id server_response и все атрибуты id моделей, уже находящихся в коллекции.

Разница id в ответе - сбор будет = добавление моделей, и наоборот будут удалены модели. Добавьте и удалите эти модели соответственно из коллекции.

Пересечение обоих наборов id будет модифицированными моделями, так что итерируйте эти id и просто выполните collection.get(id).set(attributes).

В псевдокофекте:

merge: (server_response) =>
  response_ids = _.pluck(server_response, 'id')
  collection_ids = @pluck('id')

  added = _.difference(response_ids, collection_ids)

  for add in added
    @add(_.find(server_response, (model) ->
      return model.id == add
    ))

  removed = _.difference(collection_ids, response_ids)

  for remove in removed
    @remove(@get(remove))

  changed = _.intersection(response_ids, collection_ids)

  for change in changed
    @get(change).set(_.find(server_response, (model) ->
      return model.id == change
    ))

Ответы [ 2 ]

9 голосов
/ 21 ноября 2011

Эта техника иногда полезна.Расширяем коллекцию следующим способом.Это должно сделать то, что вы ищете.Это не в кофе, но вы могли бы легко портировать его.Наслаждайтесь!

// Take an array of raw objects
// If the ID matches a model in the collection, set that model
// If the ID is not found in the collection, add it
// If a model in the collection is no longer available, remove it
freshen: function (objects) {
    var model;
    // Mark all for removal

    this.each(function (m) {
        m._remove = true;
    });

    // Apply each object
    _(objects).each(function (attrs) {
        model = this.get(attrs.id);
        if (model) {
            model.set(attrs); // existing model
            delete model._remove
        } else {
            this.add(attrs); // new model
        }
    }, this);

    // Now check for any that are still marked for removal
    var toRemove = this.filter(function (m) {
        return m._remove;
    })

    _(toRemove).each(function (m) {
        this.remove(m);
    }, this);
    this.trigger('freshen', this);
}
4 голосов
/ 26 апреля 2012

Это только что вошло в Магистральную магистраль 3 дня назад:

https://github.com/documentcloud/backbone/pull/1220

...