是否可以访问子控制器继承的服务?

时间:2015-03-09 12:53:39

标签: angularjs factory

如果父控制器注入了服务,控制器的子节点是否隐式继承服务,还是必须明确注入服务?

2 个答案:

答案 0 :(得分:3)

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

看到这个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;
}])

答案 1 :(得分:1)

如果您进行原型继承,那么您可以将父控制器中的字段作为可在派生控制器中使用的字段。为了使角度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(..)。构造函数)和控制器的定义(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>

Scoped继承

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

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

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

$scope.aService = aService

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

希望这有帮助。