我有三个非常相似的控制器。我希望有一个控制器,这三个控制器可以扩展并共享其功能。
我有三个非常相似的控制器。我希望有一个控制器,这三个控制器可以扩展并共享其功能。
Answers:
也许您不扩展控制器,但是可以扩展控制器或将单个控制器混合为多个控制器。
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,Angular依赖注入自动解决了您的顾虑。您所需要做的就是注入$ scope,尽管您可以根据需要覆盖其他注入的值。请看以下示例:
(function(angular) {
var module = angular.module('stackoverflow.example',[]);
module.controller('simpleController', function($scope, $document) {
this.getOrigin = function() {
return $document[0].location.origin;
};
});
module.controller('complexController', function($scope, $controller) {
angular.extend(this, $controller('simpleController', {$scope: $scope}));
});
})(angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>
<div ng-app="stackoverflow.example">
<div ng-controller="complexController as C">
<span><b>Origin from Controller:</b> {{C.getOrigin()}}</span>
</div>
</div>
虽然$ document在由'complexController'创建时未传递到'simpleController'中,但会为我们注入$ document。
$.extend()
,您可以致电$controller('CtrlImpl', {$scope: $scope});
angular.extend
(或$.extend
)实际上意味着$scope
仅扩展,但是如果您的基本控制器也定义了某些属性(例如this.myVar=5
),则您只能this.myVar
在使用angular.extend
handleSubmitClick
它将调用handleLogin
,而后者又具有loginSuccess
and loginFail
。所以,在我的扩展控制器然后我不得不超载handleSubmitClick
,handleLogin
以及loginSucess
正确的loginSuccess
功能使用。
对于继承,您可以使用标准的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
}
$scope.$parent.fx( )
更干净的方法,因为那是实际定义的地方?
您不扩展控制器。如果它们执行相同的基本功能,则需要将这些功能移至服务。该服务可以注入到您的控制器中。
本文采取的另一个好的解决方案:
// base controller containing common functions for add/edit controllers
module.controller('Diary.BaseAddEditController', function ($scope, SomeService) {
$scope.diaryEntry = {};
$scope.saveDiaryEntry = function () {
SomeService.SaveDiaryEntry($scope.diaryEntry);
};
// add any other shared functionality here.
}])
module.controller('Diary.AddDiaryController', function ($scope, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
}])
module.controller('Diary.EditDiaryController', function ($scope, $routeParams, DiaryService, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
$scope.diaryEntry = data;
});
}]);
您可以通过注入服务来创建服务并在任何控制器中继承其行为。
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
然后在您要从上述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()
});
DEMO PLUNKER:http ://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview
您可以扩展与服务,工厂或提供者。它们相同,但灵活性不同。
这里是使用工厂的示例:http : //jsfiddle.net/aaaflyvw/6KVtj/2/
angular.module('myApp',[])
.factory('myFactory', function() {
var myFactory = {
save: function () {
// saving ...
},
store: function () {
// storing ...
}
};
return myFactory;
})
.controller('myController', function($scope, myFactory) {
$scope.myFactory = myFactory;
myFactory.save(); // here you can use the save function
});
在这里您还可以使用存储功能:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
您可以直接使用$ controller('ParentController',{$ scope:$ scope})示例
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
您可以将Angular“ as”语法与纯JavaScript继承结合使用
在此处查看更多详细信息 http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
我写了一个函数来做到这一点:
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.
}]
)
);
}();
优点:
缺点:
我认为扩展控制器是不好的做法。而是将共享逻辑放入服务中。JavaScript中的扩展对象往往变得相当复杂。如果要使用继承,建议使用打字稿。在我看来,精简控制器是更好的选择。