Backbone JS:一个视图可以在其他视图中触发更新吗?

时间:2012-04-02 22:44:22

标签: javascript backbone.js backbone-events backbone-views

在我的简单项目中,我有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中知道选择了多少项,所以如果选择了多个项目,我会显示一个菜单供多选。

7 个答案:

答案 0 :(得分:73)

您可能希望阅读有关Backbone pub / sub events的讨论:

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

答案 1 :(得分:7)

我使用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,只是发生了事件。因此,我发现在应用程序的各个部分之间管理事件是一种可维护的方式,而不仅仅是视图。

如果您进一步了解“Facade”,可以创建一个很好的权限结构。这将允许您说只有'AppView'可以订阅我的'选定'事件。我觉得这很有用,因为它非常清楚地说明了事件的使用位置。

答案 2 :(得分:1)

忽略您在帖子中已经提到的问题,您可以绑定和触发事件到/来自全局Backbone.Event对象,这将允许任何事情与其他任何事物进行对话。绝对不是最好的解决方案,如果你有相互聊天的观点,那么你应该考虑重构。但是你去了!希望这会有所帮助。

答案 3 :(得分:1)

这是我的情况,类似的需求:Backbone listenTo似乎是一个解决方案,重定向到登录页面超时或未经过身份验证的请求。

我在路由器中添加了事件处理程序,并使其监听全局事件,例如:

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

答案 4 :(得分:1)

您可以使用Backbone对象作为事件总线。

这种方法稍微清晰但仍然依赖于Global Backbone对象

public SearcherString()
{
    Path = new List<Path>();
}

答案 5 :(得分:0)

使用相同的模型对象。可以使用集合初始化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和brandViews现在都可以访问相同的模型对象,所以当你更改一个时:

brands.get(0).selected = true;

然后,当它被引用它的视图访问时它也会改变。

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

答案 6 :(得分:0)

与John上面提到的相同,Mediator Pattern在这种情况下非常有效,因为Addy Osmani在Backbone fundamentals中再次总结了这个问题。

使用简单而且很棒的Backbone.Mediator插件重击,让我的AMD View模块无缝协同工作=)