使用服务更新2个控制器之间的共享数据

时间:2015-01-16 12:36:57

标签: javascript angularjs javascript-events angularjs-scope typescript

我有两个控制器,我想在两者之间共享数据。一个控制器支持带有表格的视图,该表格经常更改它所选择的项目"另一个使用所述项目信息从API获取数据。由于这两个控制器支持视图并且位于同一页面上,因此它们不具有经典的父/子层次结构,而是更多的兄弟姐妹'。

目前,我使用简单的事件总线'使用我在两个控制器中注入的$emit调用根作用域上的事件的服务,其中一个用$rootScope.$on监听更改。现在我多次听说这是一个糟糕的解决方案,我应该使用服务来共享数据,但是没有人真正解释如何才能看到数据的变化同时

  • 使用$watch不好
  • $broadcast不好

似乎真的要在SO上开战,哪个解决方案应该更加避免)。

我目前的解决方案:

控制器1

export class Controller1 {
    private eventBus : Components.IEventBusService;

    constructor(eventBus: Components.IEventBusService) {
        this.eventBus = eventBus;
    }

    void itemSelected(item : IItemModel) {
        this.eventBus.emit("itemSelected", { "item" : item });
    }
}

控制器2

export class Controller2 {

    constructor($scope : ng.IScope,
        eventBus : Components.IEventBusService) {

        eventBus.on("itemSelected", (event, data) =>
            this.onItemSelected(data), $scope);
    }

    private onItemSelected(data: any) {
        // do something with data.item!
    }
}

EventBusService

export interface IEventBusService {
    on(event, callback, scope): void;
    emit(event, data): void;
}

class EventBusService implements IEventBusService {

    private rootScope: ng.IRootScopeService;

    constructor($rootScope: ng.IRootScopeService) {
        this.rootScope = $rootScope;
    }

    on(event, callback, scope) : void {
        var unbind = this.rootScope.$on(event, callback);
        if(scope) {
            scope.$on("$destroy", unbind);
        }
    }

    emit(event, data) : void {
        data = data || {};
        this.rootScope.$emit(event, data);
    }

}

使用此解决方案有任何重大缺点吗?是' 服务方式'更好地更新数据等?

2 个答案:

答案 0 :(得分:2)

你是对的,应该避免$on$emit,因为它们会产生不必要的噪音。对于这种情况,实际上是一个非常简单的解决方案,我使用它很多。

您需要拥有的是服务中的对象,并为一个控制器提供对它的引用,而另一个需要触发操作的对象可以观察服务变量(顺便说一下,对TypeScript的好工作):

class ItemSelectionWrapper { //just a wrapper, you could have other variables in here if you want
    itemSelected: IItemModel;
}

class EventBusService implements IEventBusService {

    private myObj: ItemSelectionWrapper;
    ...
}

然后在你的范围内有itemSelected的控制器中(让我们假设控制器1)你引用相同的变量:

export class Controller1 {
    private eventBus : Components.IEventBusService;


    constructor(eventBus: Components.IEventBusService) {
        this.eventBus = eventBus;
        this.eventBus.myObj = this.eventBus.myObj || {};
        this.eventBus.myObj.itemSelected = $scope.itemSelected; 
    }
}

现在,由于在Controller 2中您已注入服务,因此您将观看服务的变量:

$scope.$watch(function(){
        return busService.myObj,itemSelected;
    }, function (newValue) {
        //do what you need
});

答案 1 :(得分:0)

  

是服务方式'更好地更新数据等?

是。原因是事件就像是在空中扔球并希望有人抓住它并且#34;。而服务是关于两个控制器如何交互的定义合同。

如果您使用TypeScript,您显然关心Type Safety,服务可以为您提供。


仅供参考我们内部有以下指导:

控制器之间的共享信息

当屏幕与各种占位符高度嵌套时,使用自己的" html + controller"我们需要一种在这些控制器之间共享信息(单一事实来源)的方法。

1 RootController

该部分的主控制器。负责在范围上公开SharedClass实例(允许嵌套的html段直接访问此模型)和任何顶级控制器函数。

2 SharedClass

角度服务,因为它可以轻松注入单个控制器/指令。包含在屏幕的各个部分中共享的信息/功能,例如多选模式,显示/选择的对象,变异这些对象的操作等。

3个人Html +控制器

这些子控制器可以使用简单的Angular Dependency Injection请求SharedClass。 Controller HTML应该自动访问SharedClass实例(因为RootController将其暴露给范围)。