Javascript 什么';扩展AngularJS控制器的推荐方法是什么?
我有三个非常相似的控制器。我想要一个控制器,这三个控制器可以扩展并共享其功能。您不需要扩展控制器。如果它们执行相同的基本功能,则需要将这些功能移动到服务。可以将该服务注入控制器。您可以尝试以下方法(尚未测试):Javascript 什么';扩展AngularJS控制器的推荐方法是什么?,javascript,angularjs,dry,Javascript,Angularjs,Dry,我有三个非常相似的控制器。我想要一个控制器,这三个控制器可以扩展并共享其功能。您不需要扩展控制器。如果它们执行相同的基本功能,则需要将这些功能移动到服务。可以将该服务注入控制器。您可以尝试以下方法(尚未测试): module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) { // Initialize the super class and extend it
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
// Initialize the super class and extend it.
angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
… Additional extensions to create a mixin.
}]);
对于继承,可以使用标准JavaScript继承模式。 下面是一个使用
$injector
function Parent($scope) {
$scope.name = 'Human';
$scope.clickParent = function() {
$scope.name = 'Clicked from base controller';
}
}
function Child($scope, $injector) {
$injector.invoke(Parent, this, {$scope: $scope});
$scope.name = 'Human Child';
$scope.clickChild = function(){
$scope.clickParent();
}
}
Child.prototype = Object.create(Parent.prototype);
如果您使用controllerAs
语法(我极力推荐),那么使用经典继承模式就更容易了:
function BaseCtrl() {
this.name = 'foobar';
}
BaseCtrl.prototype.parentMethod = function () {
//body
};
function ChildCtrl() {
BaseCtrl.call(this);
this.name = 'baz';
}
ChildCtrl.prototype = Object.create(BaseCtrl.prototype);
ChildCtrl.prototype.childMethod = function () {
this.parentMethod();
//body
};
app.controller('BaseCtrl', BaseCtrl);
app.controller('ChildCtrl', ChildCtrl);
另一种方法是只创建“抽象”构造函数,它将是您的基本控制器:
function BaseController() {
this.click = function () {
//some actions here
};
}
module.controller('ChildCtrl', ['$scope', function ($scope) {
BaseController.call($scope);
$scope.anotherClick = function () {
//other actions
};
}]);
好吧,我不太确定你想要实现什么,但通常服务才是你想要实现的目标。 还可以使用Angular的作用域继承特性在控制器之间共享代码:
<body ng-controller="ParentCtrl">
<div ng-controller="FirstChildCtrl"></div>
<div ng-controller="SecondChildCtrl"></div>
</body>
function ParentCtrl($scope) {
$scope.fx = function() {
alert("Hello World");
});
}
function FirstChildCtrl($scope) {
// $scope.fx() is available here
}
function SecondChildCtrl($scope) {
// $scope.fx() is available here
}
函数ParentCtrl($scope){
$scope.fx=函数(){
警报(“你好世界”);
});
}
函数FirstChildCtrl($scope){
//$scope.fx()在此处可用
}
函数SecondChildCtrl($scope){
//$scope.fx()在此处可用
}
也许您不扩展控制器,但可以扩展控制器或使单个控制器成为多个控制器的混合体
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
// Initialize the super class and extend it.
angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
… Additional extensions to create a mixin.
}]);
创建父控制器时,也会执行其中包含的逻辑。
有关更多信息,请参阅$controller(),但只需传递$scope
值。所有其他值将正常注入
@mwarren,你的问题通过角度依赖注入神奇地自动解决了。您所需要的只是注入$scope,尽管您可以根据需要重写其他注入的值。
以以下为例:
(函数(角度){
var module=angular.module('stackoverflow.example',[]);
module.controller('simpleController',函数($scope,$document){
this.getOrigin=函数(){
返回$document[0]。location.origin;
};
});
module.controller('complexController',function($scope,$controller){
extend(this,$controller('simpleController',{$scope:$scope}));
});
})(角度)代码>
来自控制器的原点:{C.getOrigin()}
您可以通过服务、工厂或提供商进行扩展。它们是相同的,但具有不同程度的灵活性
以下是使用factory的示例:
在这里,您还可以使用存储功能:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
这是另一个很好的解决方案:
只需注入服务,就可以在任何控制器中创建服务并继承其行为
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
然后在要从上述可重用代码服务扩展的控制器中:
app.controller('MainCtrl', function($scope, reusableCode) {
angular.extend($scope, reusableCode);
// now you can access all the properties of reusableCode in this $scope
$scope.commonMethod()
});
演示PLUNKER:您可以将角度“as”语法与普通JavaScript继承结合使用
请参阅此处的更多详细信息
您可以直接使用$controller('ParentController',{$scope:$scope})
范例
为此,我编写了一个函数:
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
您可以这样使用它:
function() {
var BaseController = [
'$scope', '$http', // etc.
function($scope, $http, // etc.
$scope.myFunction = function() {
//
}
// etc.
}
];
app.controller('myController',
extendController(BaseController,
['$scope', '$filter', // etc.
function($scope, $filter /* etc. */)
$scope.myOtherFunction = function() {
//
}
// etc.
}]
)
);
}();
优点:
您不必注册基本控制器
所有控制器都不需要知道$controller或$injector服务
它与angular的数组注入语法配合得很好,这对于javascript的小型化是必不可少的
您可以轻松地将额外的可注入服务添加到基本控制器,而无需记住将它们添加到所有子控制器,并从中传递它们
缺点:
基本控制器必须定义为一个变量,这有可能污染全局范围。在我的使用示例中,我通过将所有内容包装在一个匿名自执行函数中来避免这种情况,但这确实意味着所有子控制器都必须在同一个文件中声明
此模式适用于直接从html实例化的控制器,但不适用于通过$controller()服务从代码创建的控制器,因为它依赖于注入器,因此无法直接从调用代码中注入额外的非服务参数
我认为延长控制器是不好的做法。而是将共享逻辑放入服务中。javascript中的扩展对象往往变得相当复杂。如果您想使用继承,我建议您使用typescript。不过,在我看来,精简控制器是更好的选择。谢谢,但我有4个功能已经在使用服务(保存、删除等),并且在所有三个控制器中都存在相同的功能。如果扩展不是一个选项,是否有“混合”的可能性?@vladexologija我同意巴特的观点。我认为服务是混合的。您应该尝试将尽可能多的逻辑移出控制器(进入服务)。因此,如果您有3个控制器需要执行类似的任务,那么服务似乎是正确的方法。扩展控制器在Angular中感觉不自然。@vladexologija这里有一个例子来说明我的意思:它非常基本,但你会明白的。如果没有任何论证和进一步的解释,答案是毫无用处的。我还认为你有点错过了OP的要点。已经有一个共享服务。您唯一要做的就是直接公开该服务。我不知道这是不是个好主意。如果需要访问范围,您的方法也会失败。但是按照您的推理,我会将作用域作为作用域的属性显式地公开给视图,以便将其作为参数传递。一个典型的例子是,您的站点上有两个表单驱动的报表,每个报表都依赖于大量相同的数据,并且每个报表都使用大量共享服务。从理论上讲,您可以尝试将所有单独的服务放在一个包含数十个AJAX调用的大型服务中,然后使用ha
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
function() {
var BaseController = [
'$scope', '$http', // etc.
function($scope, $http, // etc.
$scope.myFunction = function() {
//
}
// etc.
}
];
app.controller('myController',
extendController(BaseController,
['$scope', '$filter', // etc.
function($scope, $filter /* etc. */)
$scope.myOtherFunction = function() {
//
}
// etc.
}]
)
);
}();