Как правильно использовать представления Backbone и маршрутизатор

У меня есть последовательность состояний страницы, которая по существу имитирует процесс проверки корзины покупок, например:

var ItemsCollection = Backbone.Collection.extend({
    model: ItemModel,    
    url "/items" 
});

var ItemsView = Backbone.View.extend({
    // Select item on click event here
});

var ItemsApp = Backbone.View.extend({
    // Fetch collection of items and render each ItemsView

});

Когда элемент выбран, я хотел существенно изменить состояние, чтобы отобразить продавцов этого предмета. Архитектура будет выглядеть так:

var SellersCollection = Backbone.Collection.extend({
    model: SellersModel,    
    url "/sellers" // The item ID is stored in a session NOT in the url (So permalinks work) 
});

var SellersView = Backbone.View.extend({
    // Select item on click event here
});

var SellersApp = Backbone.View.extend({
    // Fetch collection of sellers and render each SellersView

});

Итак, учитывая эти два состояния, где находится базовое место для создания экземпляров коллекций продавцов, выборки продавцов и отображения представления?

Я думал о том, чтобы по существу объединить представление SellersApp и представление ItemsApp в одно, служащее своего рода контроллером, который определяет, какое подпредставление отображать и какую коллекцию извлекать. Если я сделаю это таким образом, должен ли я создавать экземпляр ОБЕИХ коллекций в основном пространстве имен приложения и извлекать коллекции при необходимости, или я должен создавать экземпляр каждой коллекции только при вызове соответствующего состояния (url). Я думаю, что последний подход нарушает Закон Деметры.

Как я думаю, что я должен это сделать.

// 1. Instantiate outside the view
var MainApp  = Backbone.View.extend({

     attributes: {
         "page": "items"
     },

     items: function(){
        // Fetch items collection and render view (listenTo used in initialize)
     },

     sellers: function() {
          // Fetch sellers
     }

});

Items = new ItemsCollection;
Sellers = new SellersCollection;

Хороший ли это подход? Если это хороший подход, где я должен сообщить MainApp об изменении состояния, т.е. должен ли я явно вызывать метод сбора выборки основного приложения (т.е.
в событии «щелчок» ItemsView, явно объявить ItemsApp.sellers) или я должен используйте прослушиватель в главном представлении приложения, который автоматически прослушивает элемент, который нужно выбрать.

По сути, я ищу альтернативу использованию router.navigate-trigger и использованию маршрутизатора для создания экземпляра каждого представления/коллекции, поскольку я слышал, что это не очень хорошая практика.


person kevin    schedule 16.08.2013    source источник
comment
Я пытаюсь найти правильное решение, чтобы избежать использования встроенного в маршрутизатор метода trigger:true. Не удалось найти хороший пример.   -  person kevin    schedule 16.08.2013
comment
Вы хотите показать продавцов вместе со списком в виде расширенного представления или изменить всю страницу при выборе товара?   -  person Trevor Elliott    schedule 16.08.2013
comment
Я бы предпочел, чтобы это действовало как совершенно отдельное состояние/представление. Таким образом, это будет так же, как если бы вы щелкнули постоянную ссылку на страницу продавцов, где продавцы основаны на сохраненном элементе сеанса на стороне сервера.   -  person kevin    schedule 16.08.2013


Ответы (1)


К сожалению, с Backbone (особенно Backbone Views) не существует «правильного» способа что-то делать. Там нет ссылки соглашения. Многие люди, использующие Backbone, используют только модели/коллекции и вообще не используют представления.

На мой взгляд, я бы отказался от представления коллекции, если только она не делает что-то важное. Используйте иерархию App > ModelCollection+ModelViewCollection.

Итак, в вашем случае:

ItemsApp (Backbone.View)
--ItemCollection (Backbone.Collection)
  --Item (Backbone.Model)
    -- SellerCollection (Backbone.Collection)
--ItemViewCollection (Array)
  --ItemView (Backbone.View)
    -- SellerViewCollection (Array)

Таким образом, ваше ItemsApp будет создавать и уничтожать ItemViews по мере изменения ItemCollection (прослушивать события).

ItemView отвечает за то, чтобы знать, когда пользователь выбирает его на основе события. Затем он может выбрать заполнение коллекции SellerCollection в своей модели, когда она выбрана. Если он не выбран, эта коллекция может быть очищена. Он также отслеживает изменения в SellerCollection и добавляет и удаляет представления для каждого продавца.

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

Стоит иметь глобальный объект события, который действует как своего рода система обмена сообщениями. Backbone.View реализует Backbone.Events, поэтому вы можете объявить свой объект приложения глобально, а затем прослушивать любые события. Вы должны использовать это только тогда, когда вам нужно, в противном случае вы должны просто прослушивать события напрямую, а не запускать их глобально. Например, ваш ItemView может иметь кнопку «Назад», которая вызывает событие, называемое «назад», в то время как ваш AppView прослушивает события в активном ItemView, и когда он хочет вернуться, AppView внесет необходимые изменения в DOM и отмените выбор этого элемента.

person Trevor Elliott    schedule 16.08.2013
comment
Как это будет взаимодействовать/работать с постоянной ссылкой? Где пользователь переходит непосредственно на страницу продавца с товаром, хранящимся в сеансе на сервере? Буду ли я использовать маршрутизатор для вызова этой коллекции? Тогда он может вести себя по-другому, поскольку в описанном вами варианте использования коллекция вызывается из подпредставления, верно? - person kevin; 16.08.2013
comment
Маршрутизатор вызывает такие события, как route:detail или любое другое имя вашего маршрута, и передает аргументы этим событиям. Таким образом, ваш основной ItemsApp слушает маршрутизатор. например. router.on("route:detail", this.RouteDetail, this); - person Trevor Elliott; 16.08.2013
comment
И затем эта функция будет принимать идентификатор или что-то еще для модели элемента и устанавливать его как выбранный элемент, который должен вызвать изменение представления. По сути, вы запускаете его из события маршрутизатора ВМЕСТО одного из ваших элементов, вызывающего событие клика. Пока вы обрабатываете запуск одинаково, не должно иметь значения, как вы его запускаете. - person Trevor Elliott; 16.08.2013
comment
Таким образом, вы даже можете сделать что-то вроде... в подробном представлении элемента вы можете связать его с другим элементом. Этому представлению элемента просто нужно вызвать app.trigger("route:edit", id), чтобы приложение перешло к другому элементу. Приложение может нести ответственность за знание того, в каком состоянии оно находится (список или подробное представление) и какой элемент выбран (или нулевой), а также оно обрабатывает переходы DOM и еще много чего. - person Trevor Elliott; 16.08.2013