Tengo tres controladores que son bastante similares. Quiero tener un controlador que estos tres extiendan y compartan sus funciones.
Tengo tres controladores que son bastante similares. Quiero tener un controlador que estos tres extiendan y compartan sus funciones.
Respuestas:
Tal vez usted no se extienden un controlador, pero es posible extender un controlador o hacer un solo controlador mixin de varios 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.
}]);
Cuando se crea el controlador principal, también se ejecuta la lógica que contiene. Consulte $ controller () para obtener más información, pero solo se $scope
debe pasar el valor. Todos los demás valores se inyectarán normalmente.
@mwarren , su preocupación es atendida automáticamente por la inyección de dependencia angular. Todo lo que necesita es inyectar $ scope, aunque podría anular los otros valores inyectados si lo desea. Tome el siguiente ejemplo:
(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>
Aunque $ document no se pasa a 'simpleController' cuando es creado por 'complexController', se inyecta $ document para nosotros.
$.extend()
, simplemente puedes llamar$controller('CtrlImpl', {$scope: $scope});
angular.extend
(o $.extend
) en realidad significa extender el $scope
único, pero si su controlador base también define algunas propiedades (por ejemplo this.myVar=5
), solo tiene acceso this.myVar
en el controlador de extensión cuando usaangular.extend
handleSubmitClick
que llamaría handleLogin
a su vez que tenía un loginSuccess
y loginFail
. Por lo tanto, en mi controlador extendida después tuve sobrecargar el handleSubmitClick
, handleLogin
y loginSucess
para la correcta loginSuccess
función que se utilizará.
Para la herencia, puede usar patrones de herencia JavaScript estándar. Aquí hay una demostración 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);
En caso de que use la controllerAs
sintaxis (que recomiendo), es aún más fácil usar el patrón de herencia clásico:
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);
Otra forma podría ser crear una función de constructor "abstracta" que será su controlador base:
function BaseController() {
this.click = function () {
//some actions here
};
}
module.controller('ChildCtrl', ['$scope', function ($scope) {
BaseController.call($scope);
$scope.anotherClick = function () {
//other actions
};
}]);
Bueno, no estoy exactamente seguro de lo que quiere lograr, pero generalmente los Servicios son el camino a seguir. También puede usar las características de herencia Scope de Angular para compartir 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( )
sería una forma mucho más limpia de hacerlo, ya que es ahí donde realmente se define?
No extiendes los controladores. Si realizan las mismas funciones básicas, entonces esas funciones deben trasladarse a un servicio. Ese servicio puede inyectarse en sus controladores.
Otra buena solución tomada de este artículo :
// 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;
});
}]);
Puede crear un servicio y heredar su comportamiento en cualquier controlador con solo inyectarlo.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
Luego, en su controlador que desea extender desde el servicio reusableCode anterior:
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
Puedes probar algo como esto (no lo has probado):
function baseController(callback){
return function($scope){
$scope.baseMethod = function(){
console.log('base method');
}
callback.apply(this, arguments);
}
}
app.controller('childController', baseController(function(){
}));
Puede ampliar con un servicio , fábricas o proveedores . son iguales pero con diferente grado de flexibilidad.
Aquí un ejemplo 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
});
Y aquí también puede usar la función de tienda:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
Puede usar directamente $ controller ('ParentController', {$ scope: $ scope}) Ejemplo
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
Puede usar la sintaxis angular "como" combinada con la herencia simple de JavaScript
Ver más detalles aquí http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
Escribí una función para hacer esto:
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
Puedes usarlo así:
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.
}]
)
);
}();
Pros:
Contras:
Considero extender los controladores como una mala práctica. Más bien ponga su lógica compartida en un servicio. Los objetos extendidos en JavaScript tienden a ser bastante complejos. Si desea utilizar la herencia, le recomendaría mecanografiado. Aún así, los controladores delgados son la mejor manera de ir desde mi punto de vista.