Eu tenho três controladores que são bastante semelhantes. Eu quero ter um controlador que esses três estendam e compartilhem suas funções.
Eu tenho três controladores que são bastante semelhantes. Eu quero ter um controlador que esses três estendam e compartilhem suas funções.
Respostas:
Talvez você não estenda um controlador, mas é possível estender um controlador ou transformar um único controlador em uma mistura de vários controladores.
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.
}]);
Quando o controlador pai é criado, a lógica contida nele também é executada. Veja $ controller () para obter mais informações sobre, mas apenas os$scope
valor precisa ser passado. Todos os outros valores serão injetados normalmente.
@warwar , sua preocupação é resolvida automaticamente por injeção de dependência angular. Tudo o que você precisa é injetar $ scope, embora você possa substituir os outros valores injetados, se desejar. Veja o seguinte exemplo:
(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>
Embora $ document não seja passado para 'simpleController' quando é criado por 'complexController', o documento $ é injetado para nós.
$.extend()
, você pode simplesmente chamar$controller('CtrlImpl', {$scope: $scope});
angular.extend
(ou $.extend
) na verdade significa estender a $scope
única, mas se o seu controlador de base também define algumas propriedades (por exemplo this.myVar=5
), você só tem acesso a this.myVar
no controlador estendendo ao usarangular.extend
handleSubmitClick
que chamaria o handleLogin
que, por sua vez, tinha a loginSuccess
e loginFail
. Então, no meu controlador estendida Então eu tive que sobrecarregar o handleSubmitClick
, handleLogin
e loginSucess
para a correcta loginSuccess
função a ser usada.
Para herança, você pode usar padrões de herança JavaScript padrão. Aqui está uma demonstração que usa$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);
Caso você use a controllerAs
sintaxe (que eu recomendo), é ainda mais fácil usar o padrão de herança clássico:
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);
Outra maneira poderia ser criar apenas a função construtora "abstrata", que será seu controlador base:
function BaseController() {
this.click = function () {
//some actions here
};
}
module.controller('ChildCtrl', ['$scope', function ($scope) {
BaseController.call($scope);
$scope.anotherClick = function () {
//other actions
};
}]);
Bem, não sei exatamente o que você deseja alcançar, mas geralmente os Serviços são o caminho a percorrer. Você também pode usar as características de herança Scope do Angular para compartilhar código entre controladores:
<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( )
seria uma maneira muito mais limpa de fazê-lo, pois é onde é realmente definido?
Você não estende controladores. Se eles executam as mesmas funções básicas, essas funções precisam ser movidas para um serviço. Esse serviço pode ser injetado nos seus controladores.
Ainda outra boa solução retirada deste artigo :
// 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;
});
}]);
Você pode criar um serviço e herdar seu comportamento em qualquer controlador apenas injetando-o.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
Em seu controlador, você deseja estender o serviço reusableCode acima:
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
Você pode tentar algo como isto (não testei):
function baseController(callback){
return function($scope){
$scope.baseMethod = function(){
console.log('base method');
}
callback.apply(this, arguments);
}
}
app.controller('childController', baseController(function(){
}));
Você pode estender com serviços , fábricas ou fornecedores . eles são os mesmos, mas com diferentes graus de flexibilidade.
aqui um exemplo usando 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
});
E aqui você também pode usar a função de armazenamento:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
Você pode usar diretamente $ controller ('ParentController', {$ scope: $ scope}) Exemplo
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
Você pode usar a sintaxe Angular "como" combinada à herança simples do JavaScript
Veja mais detalhes aqui http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
Eu escrevi uma função para fazer isso:
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
Você pode usá-lo assim:
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.
}]
)
);
}();
Prós:
Contras:
Considero estender os controladores como uma má prática. Em vez disso, coloque sua lógica compartilhada em um serviço. Objetos estendidos em javascript tendem a ficar bastante complexos. Se você deseja usar herança, eu recomendaria texto datilografado. Ainda assim, controladores finos são a melhor maneira de seguir meu ponto de vista.