子控制器是否继承了对服务的访问权限?
Is access to a service inherited by child controllers?
如果父控制器注入了服务,控制器的子控制器是隐式继承服务还是必须显式注入服务?
您需要显式注入服务。子控制器继承作用域,当然服务不在作用域对象上(除非你把它放在那里)
查看这个 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;
}])
如果您进行原型继承,那么您可以从父控制器中获得一个字段,作为可以在派生控制器中使用的东西。为了使 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 控制器。然而有一个问题。例如,如果 class 栏位于不同的模块或目录中,则需要导入定义。您可以使用一些其他工具,如 RequireJS,在定义 Bar 的文件中加载 module/controller/class 定义,然后按如下方式继承。但是,您也可以使用 angularjs 结构,如下所示:
AngularJS
中的控制器继承
因此您可以使用两个 angularjs 构造来定义控制器的实例化点(angular.module(..).constructor)和控制器的定义(angular.module(. 。)。工厂)。 AngularJS 工厂可用于控制器的 class 定义。
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,因为那是 class 定义。在控制器构造中,我定义了 BaseCtrl,您可以像使用 ngController 提到的那样在外部使用它。 BaseCtrlClass 名称应该在派生控制器内部使用,我们将在下面看到。因此,正如我提到的,当您尝试在另一个 file/module 中导入 BaseCtrlClass 的定义时,问题就来了,最好是定义 DerivedCtrl class 的文件。让我们定义 DerivedCtrl Class 如下:
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。这实质上定义了控制器 class 定义。所以任何其他模块或 class 试图从这里继承都可以利用这个工厂。在构造函数中,我调用了 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 继承的 classes 访问。这样的话我提供的方案就很好用了,至少我一直在用这种方式。
希望这对您有所帮助。
如果父控制器注入了服务,控制器的子控制器是隐式继承服务还是必须显式注入服务?
您需要显式注入服务。子控制器继承作用域,当然服务不在作用域对象上(除非你把它放在那里)
查看这个 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;
}])
如果您进行原型继承,那么您可以从父控制器中获得一个字段,作为可以在派生控制器中使用的东西。为了使 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 控制器。然而有一个问题。例如,如果 class 栏位于不同的模块或目录中,则需要导入定义。您可以使用一些其他工具,如 RequireJS,在定义 Bar 的文件中加载 module/controller/class 定义,然后按如下方式继承。但是,您也可以使用 angularjs 结构,如下所示:
AngularJS
中的控制器继承因此您可以使用两个 angularjs 构造来定义控制器的实例化点(angular.module(..).constructor)和控制器的定义(angular.module(. 。)。工厂)。 AngularJS 工厂可用于控制器的 class 定义。
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,因为那是 class 定义。在控制器构造中,我定义了 BaseCtrl,您可以像使用 ngController 提到的那样在外部使用它。 BaseCtrlClass 名称应该在派生控制器内部使用,我们将在下面看到。因此,正如我提到的,当您尝试在另一个 file/module 中导入 BaseCtrlClass 的定义时,问题就来了,最好是定义 DerivedCtrl class 的文件。让我们定义 DerivedCtrl Class 如下:
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。这实质上定义了控制器 class 定义。所以任何其他模块或 class 试图从这里继承都可以利用这个工厂。在构造函数中,我调用了 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 继承的 classes 访问。这样的话我提供的方案就很好用了,至少我一直在用这种方式。
希望这对您有所帮助。