Backbone JS: может ли один просмотр запускать обновления в других представлениях? - PullRequest
45 голосов
/ 03 апреля 2012

В моем простом проекте у меня есть 2 вида - вид позиции (Бренд) и приложение.Я прикрепил функцию, которая позволяет выбирать несколько элементов:

var BrandView = Backbone.View.extend({
...some code...
    toggle_select: function() {
        this.model.selected = !this.model.selected;
        if(this.model.selected) $(this.el).addClass('selected');
        else $(this.el).removeClass('selected');
        return this;
    }
});

var AppView = Backbone.View.extend({
...some code...
    delete_selected: function() {
        _.each(Brands.selected(), function(model){ 
            model.delete_selected();
        });
        return false;
    },
});

Дело в том, я хочу знать, сколько элементов выбрано.В этой настройке выбор НЕ влияет на модель и, следовательно, не запускает никаких событий.И из концепции MVC я понимаю, что взгляды не должны напрямую говорить с другими взглядами.Так как же AppView может знать, что что-то выбирается в BrandViews?

А точнее, я AppView знаю, сколько элементов было выбрано, поэтому, если выбрано более 1, я показываю меню для множественного выбора.

Ответы [ 7 ]

73 голосов
/ 03 апреля 2012

Возможно, вы захотите прочитать это обсуждение событий Backbone pub / sub:

http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/

Мне нравится добавлять его в качестве механизма глобального события:

Backbone.pubSub = _.extend({}, Backbone.Events);

Затем в одном представлении вы можете вызвать событие:

Backbone.pubSub.trigger('my-event', payload);

А в другом можно послушать:

Backbone.pubSub.on('my-event', this.onMyEvent, this);
7 голосов
/ 03 апреля 2012

Я использую то, что Addy Osmani называет шаблоном-посредником http://addyosmani.com/largescalejavascript/#mediatorpattern. Вся статья заслуживает прочтения.

По сути, это менеджер событий, который позволяет вам подписываться и публиковать события.Таким образом, ваш AppView будет привязываться к событию, то есть к «выбранному».Затем BrandView опубликует «выбранное» событие.

Мне нравится это потому, что оно позволяет вам отправлять события между представлениями без непосредственного связывания представлений.

ДляПример

var mediator = new Mediator(); //LOOK AT THE LINK FOR IMPLEMENTATION

var BrandView = Backbone.View.extend({
    toggle_select: function() {
        ...
        mediator.publish('selected', any, data, you, want);
        return this;
    }
});

var AppView = Backbone.View.extend({
    initialize: function() {
        mediator.subscribe('selected', this.delete_selected)
    },

    delete_selected: function(any, data, you, want) {
        ... do something ...
    },
});

Таким образом, вашему представлению приложения не важно, является ли оно представлением BrandView или FooView, которое публикует событие «selected», только то, что событие произошло.В результате я считаю, что это удобный способ управления событиями между частями вашего приложения, а не только представлениями.

Если вы читаете подробнее о «Фасаде», вы можете создать хорошую структуру разрешений.Это позволит вам сказать, что только «AppView» может подписаться на мое «выбранное» событие.Я нахожу это полезным, поскольку оно очень ясно показывает, где используются события.

1 голос
/ 17 сентября 2015

Вы можете использовать объект Backbone в качестве шины событий.

Этот подход несколько чище, но все же опирается на объект Global Backbone, хотя

var view1 = Backbone.View.extend({

  _onEvent : function(){
    Backbone.trigger('customEvent');
  }

});


var view2 = Backbone.View.extend({

  initialize : function(){
    Backbone.on('customEvent', this._onCustomEvent, this);
  },

  _onCustomEvent : function(){
    // react to document edit.
  }

});
1 голос
/ 28 августа 2014

Вот мой случай с аналогичной потребностью: прослушивание Backbone казалось решением для перенаправления на страницу входа в систему по тайм-ауту или без аутентификации запросов.

Я добавил обработчик событий на свой маршрутизатор и заставил его слушать глобальное событие, такое как:

Backbone.Router.extend({
    onNotAuthenticated:function(errMsg){
        var redirectView = new LoginView();
        redirectView.displayMessage(errMsg);
        this.loadView(redirectView);
    },
    initialize:function(){
        this.listenTo(Backbone,'auth:not-authenticated',this.onNotAuthenticated);  
    },
    .....
});

и в моем обработчике ошибок jquery ajax:

$(document).ajaxError(
    function(event, jqxhr, settings, thrownError){
        .......
        if(httpErrorHeaderValue==="some-value"){
             Backbone.trigger("auth:not-authenticated",errMsg);
        }
    });     
1 голос
/ 03 апреля 2012

Игнорируя проблемы с этим, о которых вы уже упоминали в своем посте, вы можете связывать и запускать события с глобальным объектом Backbone.Event и запускать его, что позволит любому говорить с чем-либо еще. Определенно, это не лучшее решение, и если у вас есть представления, общающиеся друг с другом, то вы должны рассмотреть возможность рефакторинга. Но вы идете! Надеюсь, это поможет.

0 голосов
/ 05 сентября 2012

Так же, как Джон предлагал выше, шаблон Mediator действительно хорошо работает в этом сценарии, так как Addy Osmani снова подытоживает эту проблему в Основы основы .

Завершается с помощью Backbone.Mediator плагин, который прост и великолепен, и позволяет моим модулям AMD View работать вместе без проблем =)

0 голосов
/ 03 апреля 2012

Используйте те же объекты модели.AppView можно инициализировать с помощью коллекции, а BrandView - с одной моделью из этой коллекции.Когда атрибуты объекта ветви изменяются, любой другой код, имеющий ссылку на эту модель, может прочитать его.

Итак, у вас есть несколько брендов, которые вы выбираете через коллекцию:

var brands = new Brands([]);
brands.fetch();

Теперь вы создаете AppView и массив BrandView для каждой модели.

var appView = new AppView({brands: brands});
var brandViews = brands.map(function(brand) {
  return new BrandView({brand: brand});
});

AppView и brandView теперь имеют доступ к одним и тем же объектам модели, поэтому при изменении одного:

brands.get(0).selected = true;

Затем он изменяется при доступе к представлениям, которые также ссылаются на него.

console.log(appView.brands.get(0).selected); // true
console.log(brandViews[0].brand.selected)    // true
...