Вложенные коллекции

Backbone.js предоставляет мощный механизм для организации данных с помощью моделей и коллекций. Одним из продвинутых подходов является использование вложенных коллекций, когда модель содержит коллекцию как одно из своих свойств. Этот подход позволяет создавать сложные структуры данных, поддерживать иерархию и удобно работать с множественными уровнями вложенности.

Модели с вложенными коллекциями

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

Пример:

var Task = Backbone.Model.extend({
    defaults: {
        title: '',
        completed: false
    }
});

var TaskList = Backbone.Collection.extend({
    model: Task
});

var Project = Backbone.Model.extend({
    defaults: function() {
        return {
            name: '',
            tasks: new TaskList()
        };
    },
    
    initialize: function() {
        // Обеспечение того, что при создании модели tasks будет коллекцией
        if (!(this.get('tasks') instanceof TaskList)) {
            this.set('tasks', new TaskList(this.get('tasks')));
        }
    }
});

В этом примере модель Project содержит коллекцию TaskList в свойстве tasks. Метод initialize гарантирует, что даже если при создании передан массив объектов, он будет преобразован в полноценную коллекцию Backbone.

Работа с вложенными коллекциями

Вложенные коллекции поддерживают все стандартные методы Backbone:

var project = new Project({ name: 'Website Redesign' });

project.get('tasks').add({ title: 'Create wireframes' });
project.get('tasks').add({ title: 'Develop frontend' });

console.log(project.get('tasks').length); // 2

Методы add, remove, reset и другие работают на уровне вложенной коллекции так же, как на обычной коллекции. Это позволяет управлять задачами проекта напрямую через объект проекта.

События и вложенные коллекции

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

project.get('tasks').on('add', function(task) {
    console.log('Добавлена задача:', task.get('title'));
});

project.get('tasks').on('change:completed', function(task) {
    console.log('Задача выполнена:', task.get('title'));
});

var task = new Task({ title: 'Design logo' });
project.get('tasks').add(task);
task.set('completed', true);

В данном примере события add и change:completed срабатывают для вложенной коллекции tasks, обеспечивая реактивное обновление состояния проекта.

Сериализация вложенных коллекций

При необходимости отправки данных на сервер или сохранения в localStorage важно правильно сериализовать вложенные коллекции. Backbone.js предоставляет метод toJSON, который рекурсивно обрабатывает коллекции.

var jsonData = project.toJSON();
console.log(jsonData);
/*
{
    name: 'Website Redesign',
    tasks: [
        { title: 'Create wireframes', completed: false },
        { title: 'Develop frontend', completed: false },
        { title: 'Design logo', completed: true }
    ]
}
*/

Использование toJSON обеспечивает корректную структуру данных для передачи на сервер, включая вложенные коллекции.

Поддержка вложенных коллекций при fetch и parse

Для получения данных с сервера необходимо правильно обрабатывать вложенные коллекции в методе parse:

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

var project = new Project();
project.fetch({
    url: '/projects/1',
    success: function(model) {
        console.log(model.toJSON());
    }
});

Метод parse позволяет отделить данные коллекции от остальных атрибутов модели, автоматически создавая вложенную коллекцию и наполняя её элементами с сервера.

Управление сложными иерархиями

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

var SubTask = Backbone.Model.extend({});
var SubTaskList = Backbone.Collection.extend({ model: SubTask });

var Task = Backbone.Model.extend({
    defaults: function() {
        return { title: '', completed: false, subTasks: new SubTaskList() };
    },
    initialize: function() {
        if (!(this.get('subTasks') instanceof SubTaskList)) {
            this.set('subTasks', new SubTaskList(this.get('subTasks')));
        }
    }
});

var TaskList = Backbone.Collection.extend({ model: Task });

Такая архитектура позволяет реализовать сложные приложения с глубокими зависимостями между данными и упрощает управление состоянием через Backbone.js.

Рекомендации по работе с вложенными коллекциями

  • Всегда инициализировать вложенные коллекции в initialize или defaults, чтобы избежать проблем с сериализацией и событиями.
  • Использовать parse при работе с данными с сервера для корректной загрузки вложенных коллекций.
  • Следить за привязкой событий к вложенным коллекциям для поддержания реактивности интерфейса.
  • Для сложных иерархий рекомендуется строить отдельные коллекции для каждого уровня, чтобы избежать чрезмерной связанности и сложного кода.

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