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

Update shared data between 2 controllers with services

本文关键字:之间 共享 数据 控制器 服务 更新      更新时间:2023-09-26

我有 2 个控制器,我想在它们之间共享数据。一个控制器支持带有表的视图,该表经常更改其"选定项",另一个控制器使用所述项信息从 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!
    }
}

事件巴士服务

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

使用此解决方案有什么主要缺点吗?在更新数据等方面,"服务方式"是否更好?

你是对的,应该避免$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; 
    }
}

现在,由于在控制器 2 中您将注入服务,因此您将观察服务的变量:

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

在更新数据等方面,"服务方式"是否更好?

是的。原因是事件就像"向空中扔一个球,希望有人接住它"。而服务是关于两个控制器如何交互的定义契约。

如果你使用TypeScript,你显然关心类型安全,服务可以给你。


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

控制器之间共享信息

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

1 根控制器

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

2 共享类

一种角度服务,因为它可以很容易地注入到单个控制器/指令中。包含在屏幕的各个部分中共享的信息/功能,例如多选模式,显示/选定对象,用于更改这些对象的操作等。

3 个单独的 HTML + 控制器

这些子控制器可以使用简单的角度依赖注入来请求共享类。控制器 HTML 应该自动访问 SharedClass 实例(因为 RootController 会向范围公开该实例)。