заполнение вложенных коллекций выборкой родительской модели

#javascript #backbone.js

#javascript #backbone.js

Вопрос:

У меня есть следующая модель с вложенной коллекцией

 var Mdl = Backbone.Model.extend({
  initialize: function() {

    // collection
    this.col1 = new NestedCollection();

  },
  ...
});
  

Я хотел бы отправить данные как для модели, так и для моделей в коллекции в одном запросе, выглядящем примерно так:

 {
  att1: val,
  col1: [{obj1: val}, {...}]
}
  

Я не уверен в наилучшем способе передачи данных в запросе во вложенную коллекцию (col1). Я не могу сделать…

 var Mdl = Backbone.Model.extend({
  initialize: function() {
    // collection
    this.col1 = new NestedCollection(this.get('col1');
  },
  ...
});
  

… поскольку во время инициализации вызывается функция синтаксического анализа модели, которая не была вызвана, что означает, что атрибут col1 пуст, другим решением, о котором я подумал, было прослушивание изменений в родительской модели, например…

 model.bind("change:tags", function() {
  model.col1.refresh(model.get('col1'));
});
  

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

 this.col1.bind("add", function() {})
  

и

 this.col1.bind("remove", function() {})
  

настройка функций в коллекции.

Есть ли у кого-нибудь представление об «официальном» способе сделать это?

Спасибо.

Ответ №1:

«Официальным» способом является переопределение метода parse:

http://documentcloud.github.com/backbone/#Model-parse

В вашем конкретном случае, что я, вероятно, сделал бы, так это в методе parse создайте вложенную коллекцию из данных col1, удалите ее из результатов, затем передайте результаты дальше. Затем Backbone преобразует остальные данные в свойства.

Я не пробовал это, поэтому я не уверен на 100%, что это работает:

 parse: function(response) {
  this.col1 = new NestedCollection(response.col1);
  delete response.col1
  return response
}
  

Редактировать: 28 ноября 2012

Харм указывает, что это, возможно, не лучший способ сделать это больше. Первоначальный ответ был написан довольно давно, и в исходном вопросе указывалось, что пользователь хотел, чтобы коллекция была свойством модели (не атрибутом), но Харм считает, что использование коллекции в качестве атрибута является более приемлемым способом сделать это в наши дни.

Сегодня вы могли бы использовать что-то вроде Backbone-Relational, чтобы обрабатывать большую часть этого материала за вас, или, если вы хотите сделать это самостоятельно, и иметь коллекцию в качестве атрибута модели, вы могли бы сделать что-то вроде:

 Building = Backbone.Model.extend({
    parse: function(response) {
        console.log("Parse Called");
        response.rooms = new Rooms(response.rooms);
        return response;
    }
});
Room = Backbone.Model.extend({});
Rooms = Backbone.Collection.extend({
    model: Room
});

science_building = new Building();

science_building.fetch(
    {success: function(model,resp) {console.log(resp);}}
);
  

С помощью ответа выборки модели, подобного:

 { id: 1, 
  name: "Einstein Hall", 
  rooms: [
    {id:101, name:'Chem Lab'},
    {id:201, name:'Physics Lab'},
    {id:205, name:'Bio Lab'}
  ]
}
  

В результате получается модель построения, которая позволяет:

 science_building.get('rooms').get(101).get('name')   // ==> "Chem Lab"
  

Рабочий пример jsFiddle:http://jsfiddle.net/edwardmsmith/9bksp /

Комментарии:

1. Я не полностью согласен с этим решением. parse() должно вернуть кучу атрибутов. Теперь у этого есть какой-то странный побочный эффект установки чего-либо непосредственно в модели. Возможно, лучше заменить содержимое ключа коллекции на соответствующую базовую коллекцию.

2. У меня не работает Fiddle — добавлен jsbin jsbin.com/fafulunexe/edit?html ,js, вывод

3. Обновленный fiddle с новыми источниками CDN для backbone и подчеркивания. Спасибо, что предупредили.