J'ai trois contrôleurs assez similaires. Je veux avoir un contrôleur dont ces trois éléments étendent et partagent ses fonctions.
J'ai trois contrôleurs assez similaires. Je veux avoir un contrôleur dont ces trois éléments étendent et partagent ses fonctions.
Réponses:
Peut-être que vous n'étendez pas un contrôleur, mais il est possible d'étendre un contrôleur ou de faire d'un seul contrôleur un mixin 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 $scope
valeur doit être transmise. Toutes les autres valeurs seront injectées normalement.
@mwarren , votre préoccupation est prise en charge automatiquement par injection de dépendance angulaire. 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.
$.extend()
, vous pouvez simplement appeler$controller('CtrlImpl', {$scope: $scope});
angular.extend
(ou $.extend
) signifie en fait étendre le $scope
seul, mais si votre contrôleur de base définit également certaines propriétés (par exemple this.myVar=5
), vous n'avez accès qu'à this.myVar
dans le contrôleur d'extension lorsque vous utilisezangular.extend
handleSubmitClick
qui appellerait handleLogin
qui à son tour avait un loginSuccess
et loginFail
. Ainsi, dans mon contrôleur étendu , je devais alors surcharger le handleSubmitClick
, handleLogin
et loginSucess
pour la bonne loginSuccess
fonction à utiliser.
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 controllerAs
syntaxe (que je recommande vivement), il est encore plus facile 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 simplement 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 sais pas exactement ce que vous voulez atteindre, mais les services sont généralement la voie à suivre. Vous pouvez également utiliser les caractéristiques d'héritage de portée d'Angular pour partager du 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
}
$scope.$parent.fx( )
une façon beaucoup plus propre de le faire, puisque c'est là que cela est réellement défini?
Vous n'étendez pas les contrôleurs. S'ils exécutent 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 bonne solution tirée de cet 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 que vous souhaitez étendre à partir du 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()
});
DÉMO PLUNKER: http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview
Vous pouvez essayer quelque chose comme ça (je n'ai pas 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 des services , des usines ou des fournisseurs . ils sont identiques mais avec un degré de flexibilité différent.
voici un exemple utilisant l'usine: 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 utiliser directement $ 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});
}]);
Vous pouvez utiliser la syntaxe angulaire "en tant que" associée à l'héritage JavaScript brut
Voir plus de détails ici http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
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:
Les inconvénients:
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 à devenir plutôt complexes. Si vous souhaitez utiliser l'héritage, je recommanderais dactylographié. Pourtant, les contrôleurs minces sont la meilleure façon d'aller de mon point de vue.