Skip to content

Latest commit

 

History

History
183 lines (155 loc) · 10.3 KB

6.collection_and_views.md

File metadata and controls

183 lines (155 loc) · 10.3 KB

6.1 Коллекции и представления

6.2 Представление коллекции

Задание. Пришло время начать строительство нашего приложения Appointment. Мы будем использовать коллекцию и представление коллекции для отображения списка встреч раздражительного, но замечательного Dr. Goodparts.
Начнём с создания класса представления AppointmentListView, а затем его экземпляра с аргументом appointments.

Решение. Создадим переменную AppointmentListView и присвоим ей класс представления. Затем экземпляр этого класса присвоим переменной newAppointmentListView и передадим ему свойство collection со значением appointments:

var Appointment = Backbone.Model.extend({});

var AppointmentList = Backbone.Collection.extend({
    model: Appointment
});
var appointments = new AppointmentList();

var AppointmentListView = Backbone.View.extend({});
var newAppointmentListView = new AppointmentListView({
    collection: appointments
});

Пояснение. При создании представления колекции мы передаём во view не модель, а коллекцию.

6.3 Отображение коллекции

Задание. Пойдём дальше и реализуем функцию addOne, отображающую AppointmentView для каждой модели в коллекции и добавляющую его в верхнеуровневый элемент представления коллекции.
На заметку: В вызове forEach ошибка, убедимся, что она исправлена перед отправкой.
Views:

var AppointmentView = Backbone.View.extend({
    template: _.template('<span class="<%= if(cancelled) print("cancelled") %>">' +
        '<%= title %></span>' +
        '<a href="#">x</a>'),

    render: function () {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

application.js:

var AppointmentListView = Backbone.View.extend({
    render: function () {
        this.collection.forEach(this.addOne);
    },
    addOne: function (model) {

    }
});

Решение. В вызов forEach добавим, вторым аргументом, this. Заполним тело функции addOne: создадим экземпляр appointmentView класса View с переменной model в качестве значения свойства model; применим метод append() с рендерингом верхнеуровневых элементов экземпляра:

var AppointmentListView = Backbone.View.extend({
    render: function () {
        this.collection.forEach(this.addOne, this);
    },
    addOne: function (model) {
        var appointmentView = new AppointmentView({model: model});
        this.$el.append(appointmentView.render().el);
    }
});

Пояснение. С помощью второго аргумента метода forEach(), в качестве которого выступает this, мы сохраняем правильный контекст.

6.4 Внутри DOM

Задание. Посмотрим, как окупается рендеринг представления коллекции и вставка его в DOM. Используя append или методы html jQuery, вставим элемент верхнего уровня в #app div.

Решение. Выберем DOM элемент #app и применим к нему вызов метода html, в аргументе которого сделаем рендеринг элементов первого уровня экземпляра appointmentsView:

var appointmentsView = new AppointmentListView({collection: appointmentList});
$('#app').html(appointmentsView.render().el);

Пояснение. Для рендеринга элемента верхнего уровня класса (или экземпляра) View в конкретном элементе DOM можно воспользоваться методом выбора jQuery.

6.5 Добавление новых моделей

Задание. Dr. Goodparts снова добавил нобые модели в коллекцию, но его планы были нарушены, потому что при добавлении модели DOM не обновлялся.
В функции initialize AppointmentListView's, прослушаем событие add для коллекции и вызовем функцию addOne для добавления новой модели во view.
Убедимся, что мы включили аргумент контекста для гарантии, что addOne вызовется с корректным контекстом.

Решение. В теле функции initialize прослушаем событие add для коллекции, вызовем функцию addOne и включим аргумент контекста:

var AppointmentListView = Backbone.View.extend({
    initialize: function () {
        this.collection.on('add', this.addOne, this);
    },
    render: function () {
        this.collection.forEach(this.addOne, this);
    },
    addOne: function (model) {
        var appointmentView = new AppointmentView({model: model});
        appointmentView.render();
        this.$el.append(appointmentView.el);
    }
});

Пояснение. С таким примером мы уже сталкивались, когда создавали прослушивание для изменения модели во view. Подобным образом initialize работает и с коллекциями.

6.6 Сброс всех вещей

Задание. Понедельник - время сбросить все встреч за неделю. Внизу слышно визжание покрасневшего от злости Dr. Goodparts, потому что DOM не обновляется при удалении коллекции.
Модифицируем AppointmentListView для прослушивания события reset из коллекции для вызова функции render.
Убедимся, что мы включили аргумент контекста для гарантии, что addOne вызовется с корректным контекстом.

Решение. Добавим в initialize ещё одно событие (reset), но при его реализации будет выполняться render:

var AppointmentListView = Backbone.View.extend({
    initialize: function () {
        this.collection.on('add', this.addOne, this);
        this.collection.on('reset', this.render, this);
    },
    render: function () {
        this.collection.forEach(this.addOne, this);
    },
    addOne: function (model) {
        var appointmentView = new AppointmentView({model: model});
        appointmentView.render();
        this.$el.append(appointmentView.el);
    }
});

Пояснение. Таким же образом как добавления, можно прослушивать удаления и любые другие события.

6.7 Удаление модели

Задание. Оказывается, одна из встреч в нашей коллекции была перенесена на следующую неделю, но, когда Dr. Goodparts удалил её модель из коллекции, она не удалилась из DOM. Можно представить себе реакцию Dr. Goodparts...
Устраним этот баг, используя пользовательское событие hide на моделях Appointment.
Обновим коллекцию AppointmentList для триггера события hide на model при её удалении.
Обновим AppointmentView для вызова функции remove всякий раз, когда модель включает событие event.

Решение. В классе Collection создадим функцию initialize, которая будет прослушивать удаление и реагировать на него срабатыванием пользовательского события hide. Во View определим это событие, как скрывающее удалённый элемент:
Collection:

var AppointmentList = Backbone.Collection.extend({
    model: Appointment,
    initialize: function () {
        this.on('remove', this.hideModel);
    },
    hideModel: function (model) {
        model.trigger('hide');
    }
});

View:

var AppointmentView = Backbone.View.extend({
    initialize: function () {
        this.model.on('hide', this.remove, this);
    },
    remove: function () {
        this.$el.remove();
    }
});

Пояснение. Между моделями, контролерами и представлениями в Backbone существует крепкая взаимная связь. Каждая модель имеет своё представление, а представление - свою модель, контролер же охватывает их все. Поэтому в коде все эти классы и их экземпляры постоянно будут ссылаться друг на друга.
Метод trigger() вызывает срабатывание события. В нашем случае, в контролере срабатывает событие hide, определённое в представлении.