J'ai trois contrôleurs qui sont assez similaires. Je veux avoir un contrôleur qui ces trois étendent et partagent ses fonctions.
Peut-être que vous n’étendez pas un contrôleur, mais il est possible d’agrandir un contrôleur ou de transformer un seul contrôleur en une combinaison de plusieurs contrôleurs.
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.
}]);
Lorsque le contrôleur parent est créé, la logique qu'il contient est également exécutée. Voir $ controller () pour plus d'informations sur mais seule la valeur $scope
doit être transmise. Toutes les autres valeurs seront injectées normalement.
@ mwarren, votre problème est traité automatiquement par magie par Angular injection de dépendance. Tout ce dont vous avez besoin est d'injecter $ scope, bien que vous puissiez remplacer les autres valeurs injectées si vous le souhaitez. Prenons l'exemple suivant:
(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>
Bien que $ document ne soit pas passé dans 'simpleController' lorsqu'il est créé par 'complexController', $ document est injecté pour nous.
Pour l'héritage, vous pouvez utiliser des modèles d'héritage JavaScript standard. Voici une démo qui utilise $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);
Si vous utilisez la syntaxe controllerAs
(ce que je recommande vivement), il est encore plus simple d'utiliser le modèle d'héritage classique:
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);
Une autre façon pourrait être de créer une fonction constructeur "abstraite" qui sera votre contrôleur de base:
function BaseController() {
this.click = function () {
//some actions here
};
}
module.controller('ChildCtrl', ['$scope', function ($scope) {
BaseController.call($scope);
$scope.anotherClick = function () {
//other actions
};
}]);
Eh bien, je ne suis pas tout à fait sûr de ce que vous voulez réaliser, mais généralement, les services sont la voie à suivre. Vous pouvez également utiliser les caractéristiques d'héritage Scope de Angular pour partager le code entre les contrôleurs:
<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
}
Vous n'allongez pas les contrôleurs. S'ils remplissent les mêmes fonctions de base, ces fonctions doivent être déplacées vers un service. Ce service peut être injecté dans vos contrôleurs.
Encore une autre bonne solution tirée de ceci article :
// 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;
});
}]);
Vous pouvez créer un service et hériter de son comportement dans n'importe quel contrôleur simplement en l'injectant.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
Ensuite, dans votre contrôleur, vous souhaitez étendre le service reusableCode ci-dessus:
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
Vous pouvez essayer quelque chose comme ceci (ne pas avoir testé):
function baseController(callback){
return function($scope){
$scope.baseMethod = function(){
console.log('base method');
}
callback.apply(this, arguments);
}
}
app.controller('childController', baseController(function(){
}));
Vous pouvez étendre avec un service , des usines ou fournisseurs . ils sont identiques mais avec un degré de flexibilité différent.
voici un exemple utilisant factory: 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
});
Et ici, vous pouvez également utiliser la fonction de stockage:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
Vous pouvez directement utiliser $ controller ('ParentController', {$ scope: $ scope}) Exemple
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
J'ai écrit une fonction pour faire ceci:
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
Vous pouvez l'utiliser comme ceci:
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.
}]
)
);
}();
Avantages:
inconvénients:
Vous pouvez utiliser la syntaxe Angular "en tant que" associée à un héritage JavaScript simple.
Voir plus de détails ici http://blogs.Microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
Je considère l'extension des contrôleurs comme une mauvaise pratique. Mettez plutôt votre logique partagée dans un service. Les objets étendus en javascript ont tendance à être plutôt complexes. Si vous souhaitez utiliser l'héritage, je recommanderais TypeScript. Néanmoins, les contrôleurs minces sont un meilleur moyen d’aller de mon point de vue.