如果父控制器注入了服务,控制器的子节点是否隐式继承服务,还是必须明确注入服务?
答案 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的类访问。在这种情况下,我提供的解决方案效果很好,至少我一直在使用这种方式。
希望这有帮助。