如何在控制器之间进行通信而不在它们之间使用SharedService?

时间:2014-08-18 13:05:55

标签: angularjs angularjs-directive angularjs-scope angular-ui

我正在阅读有关控制器和指令之间通信的所有答案,但在我看来似乎是使用共享服务并将其注入其中的每一个。当我开发一个非常大规模的应用程序时,我不知道我的页面会包含哪些内容。我可能有2个控制器需要在它们之间进行通信,而且我也可能在同一页面中有5个指令和2个控制器。我从头开始不知道我的视图/页面中会有什么内容,因此我需要一种更好的方法来如何在它们之间进行通信。我正在寻找更好的方法,正确的AngularJS方式。

http://i60.tinypic.com/2z87q05.png

以上是我的观点示例我正在处理:在左侧我有一个指示树,在右侧我有图表控制器和指令网格。我可能有更多,但这是我可能拥有的一个很好的例子。请记住,视图可以包含X个组件,您从一开始就不知道其中的内容。

现在,让我们说每次在左侧的树中选择节点时,我希望能够告诉其他控制器nodeSelectedChange事件发生。我不想给他们每个人注入一个包含该信息的服务,所以我想到了一个类似于所有视图之父的页面管理器控制器。我的页面中的所有控制器/指令都应该只通过PageManagerController相互通信,他是页面中唯一知道他内在的东西的东西。

重要的是要记住:树不知道页面有图表或网格,他们不需要彼此了解才能进行交流。页面管理器知道一切,现在我想让它变得神奇 - 它应该有服务吗?是否每个其他组件都有服务和服务可以与PageManager服务通信?

帮助我思考。希望我可以连接所有的点,以创建一个更好的沟通方式。 我认为sharedService方式适用于小型应用程序,当您从一开始就知道应用程序中发生了什么,但大部分时间 - 您只是不知道谁将何时使用您的指令,它应该能与所有人交谈。

关于活动我不喜欢什么:

  1. 在控制器内部触发的事件,而它应该在服务中。
  2. 听众控制器应该知道他要听的事件的名称。如果我将事件名称更改为$ emit或$ broadcast,我需要在所有应用程序中遍历所有听众$(" eventName")并更改为该唯一名称。
  3. 指令就像一个黑盒子,我不想每次检查它内部,并找到他正在播放的事件的名称,以便与之通信。
  4. 我需要一种方法来将指令中的事件NAMES暴露出来,可能是连接到该控制器的服务。

3 个答案:

答案 0 :(得分:2)

有几个好的做法:

  1. 使用$scope运行时依赖项的指令和控制器之间进行通信(例如,从服务器获取的模型,实例化的类等)。要做的就是使用隔离范围,并将属性映射到依赖项:

    directive('tree', function(){
      return {
        scope: {
          somevalue : "="
        }
      }
    });
    

    像这样使用:

    <tree somevalue="objectFromController">
    
  2. 使用注入服务静态依赖关系(Presentation Models,全局可共享状态等)进行通信。

    directive('tree', function(treeState){
      return {
        scope: {
          somevalue : "="
        },
        link: function(scope){
          // some logic updating the treeState
          treeState.openNodes = ['x', 'y'];
        }
      }
    });
    
    controller('ctrl', function($scope, treeState){
      // react to treeState changes
      // you can use $scope.$watch for it
      // or any other way you like
      // see: https://github.com/mr-mig/angular-react-to
    
    });
    
  3. 如果您想拥有最大可合成性,请坚持使用第一种模式:

    directive('tree', function(){
      return {
        scope: {
          model : "="
        },
        link: function(scope){
          // some logic updating the treeState, stored as scope.model
          scope.model.openNodes = ['x', 'y'];
        }
      }
    });
    
    controller('ctrl', function($scope, treeFactory){
      $scope.treeModel = treeFactory.create();
      // react to treeState changes
      // you can use $scope.$watch for it
      // or any other way you like
      // see: https://github.com/mr-mig/angular-react-to
    });
    

    使用模板和绑定作为通信总线来编写这些东西:

    <tree model="treeModel">
    

  4. 坚持这种模式,你得到:

    1. 没有活动
    2. 定义明确的指令“interface”(隔离范围内的属性)
    3. 易于组合
    4. 基于范围变更传播的反应行为

答案 1 :(得分:1)

这实际上取决于您希望从树指令共享到页面其他部分的信息类型。

你面前有几个选择:

使用范围事件

如上所述,您可以触发事件并监听各种控制器和/或服务中的事件。也就是说,它可以变得非常丑陋,非常快。跟踪事件并确定哪些事件监听器在给定点活跃,可以为最好的工程师提供偏头痛!

使用服务

另一个选择是使用服务,让我们说一个PageManagerService。在那种情况下,

  • 每次点击树项目都会在PageManagerService上设置一些信息,说明哪个页面,哪些对象以及需要显示哪些项目
  • 需要更改的每个组件都可以
    • 注册在PageManagerService更改时触发的侦听器
    • 在服务上添加监视并在PageManagerService更改时运行其代码

服务本身将成为共享状态,它将取决于它如何消费和响应状态变化的指令和组件。

使用UI路由器

但是我越是想到这一点,它就越像是 UI Router 这样的好用例。 UI路由器允许您定义状态,并使页面的不同部分以不同的方式响应状态更改。每个部分都可以通过加载

以自己的方式响应状态变化
  • 不同的控制器
  • 一个不同的模板,可能包含不同的组件和小部件

所以你最终得到的是一个带

的结构
  • 左侧的Tree指令
  • 以ui-view命名,让我们说,顶部
  • 一个ui-view命名,让我们说,底部

树指令中的每个项目都可以是 ui-sref ,这只是一种奇特的方式,而不是重定向到URL,重定向到状态。

然后,您可以在一个地方定义应用程序中的配置,如下所示:

$stateProvider.state('dashboard', {
  views: {
    "top": { templateUrl: 'my/dashboard.html', controller: 'DashboardCtrl'}
    "bottom": { templateUrl: 'my/dashboard-grid.html', controller: 'DashboardGridCtrl'}
  }
})

同样,您可以为树指令中的每个项目设置一个状态定义,每个项目只是一个指向不同状态的链接。

当然,状态定义是在AngularJS应用程序的 config 部分完成的,您应该知道它是在应用程序启动之前。如果你还需要动态状态怎么办?

嗯,一些答案/想法也会引导你走下去:

  • 必须预定义控制器和服务,不会动态创建HTML内容和/或JS控制器
  • 可以在配置部分中将$ stateProvider公开为全局变量,并在控制器/服务内动态调用stateProvider.state,无论您有新的状态定义。
  • 通常,控制器和HTML保持不变,我们只需要使用各种参数触发不同的状态。这可以通过调用 transitionTo 函数转换到具有各种状态参数的已定义状态来轻松完成。

答案 2 :(得分:0)

你可以使用$ on,$ emit和$ broadcast在不同的控制器/范围之间进行通信。

请关注我之前的帖子。我有一个设置插件。你可以试试这个例子。 Angular Js newbie - link in a controller view that triggers another controller action

$on : setup a event handler
$emit : communicate to parent controllers
$broadcast : communicate to child controllers

了解更多访问 - https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope

相关问题