【问题标题】:Is access to a service inherited by child controllers?对服务的访问权是否由子控制器继承?
【发布时间】:2015-03-09 12:53:38
【问题描述】:

如果父控制器注入了服务,控制器的子控制器是隐式继承服务还是必须显式注入服务?

【问题讨论】:

    标签: angularjs factory


    【解决方案1】:

    您需要明确地注入服务。子控制器继承了作用域,但是服务当然不在作用域对象上(除非你把它放在那里)

    查看这个 jsfiddle 来证明它:http://jsfiddle.net/HB7LU/11596/

    var myApp = angular.module('myApp',[]);
    
    myApp.factory('serviceId', function() {
      var a = 1;
        return {
            a: a
        };
    });
    
    myApp.controller('Ctrl',['$scope', 'serviceId' ,function($scope, serviceId) {
        $scope.name = 'Superhero' + serviceId.a;
    }])
    
    myApp.controller('ChildCtrl',['$scope',function($scope) {
    
        // the next line throws an undefined error because of serviceId
        $scope.name = 'Superhero' + serviceId.a;
    }])
    

    【讨论】:

      【解决方案2】:

      如果您进行原型继承,那么您可以从父控制器中获得一个字段,作为可以在派生控制器中使用的东西。为了使 Angular js 控制器可继承,您必须做一些事情。希望下面的解释会更清楚。

      JavaScript 中的原型继承

      所以首先让我们定义我们将如何从原型继承对象。在 javascript 中,原型继承可以按如下方式完成:

      function Foo(some_param)
      {
          this.some_param = some_param
      }
      
      function Bar(some_param, some_specialized_param)
      {
          /**
           * Call the super class constructor
           */
          Foo.call(this, some_param);
          this.some_specialized_param = some_specialized_param;
      }
      
      /**
       * Now that you have defined the constructor, you need to
       * define the prototypical inheritance
       */
      Bar.prototype = Object.create(Foo.prototype);
      
      /**
       * Now you have to set the constructor
       */ 
      Bar.prototype.constructor = Bar;
      

      所以使用这个例子你可以创建 angularjs 控制器。然而有一个问题。例如,如果类 Bar 位于不同的模块或目录中,则需要导入定义。您可以使用其他工具(如 RequireJS)将模块/控制器/类定义加载到定义 Bar 的文件中,然后按如下方式继承。但是,您也可以使用 angularjs 结构,如下所示:

      AngularJS 中的控制器继承

      因此,您可以使用两个 angularjs 构造来定义控制器的实例化点(angular.module(..).constructor)和控制器的定义(angular.module(..).factory)。 AngularJS 工厂可用于控制器的类定义。

      angular.module('some_module')
      .factory('BaseCtrlClass', ['aService', function(aService)
      {
          function BaseCtrl($scope)
          {
              /**
               * Assign a reference to "aService"
               * which is injected whithin this factory
               */
              this.aService = aService;
              this.$scope = $scope;
          }
      
          return BaseCtrl;
      }]);
      

      现在您可以定义一个控制器定义,以便您可以使用 ngController 实例化它,例如:

      angular.module('some_module')
      .controller('BaseCtrl', [$scope, 'BaseCtrlClass', function($scope, BaseCtrlClass)
      {
          return new BaseCtrlClass($scope);
      }]);
      

      请注意,在工厂中,我已将其定义为 BaseCtrlClass,因为这是类定义。在控制器构造中,我定义了 BaseCtrl,您可以使用 ngController 在外部使用它。 BaseCtrlClass 名称应该在派生控制器内部使用,我们将在下面看到。因此,正如我提到的,当您尝试在另一个文件/模块中导入 BaseCtrlClass 的定义时,问题就出现了,理想情况下是定义 DerivedCtrl 类的文件。让我们定义 DerivedCtrl 类如下:

      angular.module('a_different_module')
      .factory('DerivedCtrlClass', ['BaseCtrlClass', function(BaseCtrlClass)
      {
          function DerivedCtrl($scope, aDifferentService)
          {
              BaseCtrlClass.call(this, $scope);
              this.aDifferentService = aDifferentService //Specialized resource
          }
      
          DerivedCtrl.prototype = Object.create(BaseCtrlClass.prototype);
          DerivedCtrl.prototype.constructor = DerivedCtrl;        
      
          return DerivedCtrl; 
      }])
      .controller('DerivedCtrl', ['$scope', 'aDiferentService', 'DerivedCtrlClass', function($scope, aDifferentService, DerivedCtrlClass)
      {
          return new DerivedCtrlClass($scope, aDifferentService);
      }]);
      

      所以在这里你可以看到我已经在一个名为 DerivedCtrlClass 的工厂中定义了 DerivedCtrl。这实质上定义了控制器类定义。所以任何其他试图从它继承的模块或类都可以利用这个工厂。在构造函数中,我调用了 BaseCtrlClass 的构造函数,根据需要传递“this”和“$scope”作为参数。后来我定义了原型构造和默认构造函数,类似于我之前提到的 javascript 示例。为了方便起见,我还定义了一个控制器结构,它也可以与 ngController 一起使用。

      我要强调的要点是 DerivedCtrl 的实例现在可以使用

      this.aService
      

      这是在 BaseCtrl 中定义的。基本上,在 BaseCtrl 和 DerivedCtrl 范围内定义的任何内容现在都可以在 DerivedCtrl 的实例中使用。当您尝试定义 DerivedCtrl 时,这在 html 中非常有效

      <div ng-controller="DerivedCtrl">
          ......
      </div>
      

      范围继承

      如果你想拥有范围继承,你可以使用这样的东西:

      <div ng-controller="BaseCtrl">
          <div ng-controller="DerivedCtrl">
              ...
          </div>
      </div>
      

      这样做的问题是您需要使用 $scope 来传递字段。在 BaseCtrl 的构造函数中,您需要执行以下操作:

      $scope.aService = aService
      

      然后您可以从 DerivedCtrl 使用 $scope.aService。这不能很好地工作,因为它破坏了封装。为了可维护性,您可能不希望导出此服务并使其伪受保护,以便仅由继承自 BaseCtrl 的类访问。在那种情况下,我提供的解决方案效果很好,至少我一直在使用这种方式。

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-29
        • 1970-01-01
        • 1970-01-01
        • 2011-12-05
        • 2016-12-09
        • 2010-09-28
        相关资源
        最近更新 更多