什么是推荐的方式来扩展AngularJS控制器?

我有三个非常相似的控制器。 我想有一个控制器,这三个扩展和分享它的function。

也许不扩展一个控制器,但是可以扩展一个控制器或者使一个控制器成为多个控制器的混合。

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. }]); 

当父控制器被创build时,其中包含的逻辑也被执行。 有关更多信息,请参阅$ controller(),但只有$scope值需要传递。 所有其他值将被正常注入。

@mwarren ,你的关心是由angulardependency injection自动神奇照顾。 所有你需要的是注入$ 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="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> 

对于inheritance,您可以使用标准的JavaScriptinheritance模式。 这是一个使用$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语法(我强烈build议),使用经典的inheritance模式更加容易:

 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); 

另一种方法可能是创build只是“抽象”的构造函数,这将是您的基础控制器:

 function BaseController() { this.click = function () { //some actions here }; } module.controller('ChildCtrl', ['$scope', function ($scope) { BaseController.call($scope); $scope.anotherClick = function () { //other actions }; }]); 

关于这个主题的博客文章

那么,我不完全确定你想达到什么,但通常服务是要走的路。 您还可以使用Angular的Scopeinheritance特性在控制器之间共享代码:

 <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 } 

你不扩展控制器。 如果他们执行相同的基本function,那么这些function需要转移到服务。 该服务可以注入您的控制器。

从这篇文章中获得另一个好的解决scheme:

 // 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; }); }]); 

您可以创build一个服务,并通过注入来inheritance其在任何控制器中的行为。

 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

你可以尝试像这样(没有testing过):

 function baseController(callback){ return function($scope){ $scope.baseMethod = function(){ console.log('base method'); } callback.apply(this, arguments); } } app.controller('childController', baseController(function(){ })); 

你可以直接使用$ 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}); }]);

您可以扩展与服务工厂提供商 。 他们是相同的,但具有不同程度的灵活性。

这里使用工厂的一个例子: 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 }); 

在这里你也可以使用商店function:

 <div ng-controller="myController"> <input ng-blur="myFactory.store()" /> </div> 

您可以使用Angular“as”语法与纯JavaScriptinheritance相结合

在这里看到更多的细节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. }] ) ); }(); 

优点:

  1. 您不必注册基本控制器。
  2. 没有一个控制器需要知道$控制器或$注入器服务。
  3. 它适用于angular的数组注入语法 – 如果您的javascript将被缩小,这是非常重要的。
  4. 您可以轻松地为基础控制器添加额外的注射服务, 不必记住将其添加到所有的子控制器,并将其传递通过它们。

缺点:

  1. 基础控制器必须被定义为一个variables,这可能会污染全球范围。 我在我的用法示例中避免了这一点,方法是将所有内容都包含在一个匿名的自执行函数中,但是这意味着所有的子控制器都必须在同一个文件中声明。
  2. 这种模式适用于直接从你的html实例化的控制器,但是对于你通过$ controller()服务从你的代码创build的控制器不是那么好,因为它依赖于注入器阻止你直接注入额外的非服务参数从您的调用代码。

我认为把控制器扩展为不好的做法。 而是把你的共享逻辑放到一个服务中。 JavaScript中的扩展对象往往会变得相当复杂。 如果你想使用inheritance,我会推荐打字稿。 尽pipe如此,瘦控制器是更好的方式去我的观点。