В Backbone.js nested модели (вложенные модели) позволяют структурировать данные, создавая иерархию объектов, где одна модель может содержать другие модели или коллекции. Это особенно актуально при работе с сложными JSON-структурами, получаемыми от сервера. Прямой поддержки вложенных моделей в Backbone нет, поэтому требуется ручная организация и расширение стандартных возможностей фреймворка.
В Backbone каждая модель хранит данные в объекте
attributes. При стандартном определении модели все поля
являются примитивами или объектами JavaScript. Для работы с вложенными
моделями необходимо:
parse, toJSON и
иногда set, чтобы правильно обрабатывать вложенные
структуры.Пример базовой вложенной модели:
var Address = Backbone.Model.extend({
defaults: {
street: '',
city: '',
zipcode: ''
}
});
var User = Backbone.Model.extend({
defaults: function() {
return {
name: '',
email: '',
address: new Address()
};
},
parse: function(response) {
if (response.address) {
this.get('address').set(response.address);
delete response.address;
}
return response;
},
toJSON: function() {
var json = _.clone(this.attributes);
json.address = this.get('address').toJSON();
return json;
}
});
В этом примере User содержит вложенную модель
Address. Метод parse обрабатывает данные от
сервера, а toJSON обеспечивает корректную сериализацию для
отправки обратно.
1. Инициализация через конструктор
Nested модель можно передавать при создании родительской модели:
var user = new User({
name: 'Иван',
email: 'ivan@example.com',
address: new Address({ street: 'Ленина', city: 'Москва', zipcode: '101000' })
});
2. Обновление данных вложенной модели
user.get('address').set({ city: 'Санкт-Петербург' });
Важно помнить, что set на родительской модели для
вложенного объекта без правильного переопределения set не
обновит сам объект Address, а заменит его обычным
объектом.
3. Автоматическое создание вложенных моделей
Можно переопределить set, чтобы автоматически
конвертировать обычные объекты в вложенные модели:
set: function(key, val, options) {
var attrs = key;
if (key === Object(key) && !(key instanceof Backbone.Model)) {
attrs = key;
} else {
attrs = {};
attrs[key] = val;
}
if (attrs.address && !(attrs.address instanceof Address)) {
attrs.address = new Address(attrs.address);
}
return Backbone.Model.prototype.set.call(this, attrs, options);
}
Это гарантирует, что любое присваивание обычного объекта
address будет преобразовано в модель
Address.
Nested структуры могут включать не только модели, но и коллекции. Пример:
var Task = Backbone.Model.extend({
defaults: { title: '', done: false }
});
var TaskList = Backbone.Collection.extend({
model: Task
});
var Project = Backbone.Model.extend({
defaults: function() {
return {
name: '',
tasks: new TaskList()
};
},
parse: function(response) {
if (response.tasks) {
this.get('tasks').reset(response.tasks);
delete response.tasks;
}
return response;
},
toJSON: function() {
var json = _.clone(this.attributes);
json.tasks = this.get('tasks').toJSON();
return json;
}
});
Использование:
var project = new Project({
name: 'Backbone Tutorial',
tasks: [
{ title: 'Изучить модели', done: true },
{ title: 'Изучить коллекции', done: false }
]
});
Методы reset, add, remove
коллекции позволяют управлять элементами динамически, сохраняя структуру
данных.
Для корректного реагирования на изменения вложенных данных важно использовать слушатели событий:
var user = new User({
name: 'Анна',
address: new Address({ street: 'Пушкина', city: 'Казань', zipcode: '420000' })
});
user.get('address').on('change', function() {
console.log('Адрес изменён:', this.toJSON());
});
user.get('address').set({ city: 'Нижний Новгород' });
При этом изменение вложенной модели вызывает событие только на самой модели, а не на родительской. Если нужно, чтобы родительская модель также реагировала, создаются прокси-обработчики:
initialize: function() {
this.listenTo(this.get('address'), 'change', this.onAddressChange);
},
onAddressChange: function() {
this.trigger('change:address', this, this.get('address'));
}
parse для корректного
преобразования данных с сервера.toJSON для сохранения вложенной
структуры при отправке на сервер.reset при инициализации и
загрузке данных.listenTo вместо прямого on для
удобного управления жизненным циклом событий.Nested модели делают Backbone мощным инструментом для управления сложными клиентскими данными, позволяя сохранять иерархическую структуру и обеспечивать реактивное обновление интерфейса.