javascript - varios - ¿Cuál es la forma recomendada de extender los controladores AngularJS?
varios controladores angularjs (12)
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 de Ángulo 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
}
Tengo tres controladores que son bastante similares. Quiero tener un controlador que estos tres amplíen y compartan sus funciones.
Considero que extender los controladores es una mala práctica. En lugar de poner su lógica compartida en un servicio. Los objetos extendidos en javascript tienden a ser bastante complejos. Si desea usar herencia, recomendaría mecanografiado. Aún así, los controladores delgados son una mejor manera de ir en mi punto de vista.
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:
- No es necesario que registre el controlador base.
- Ninguno de los controladores necesita saber acerca de los servicios $ controller o $ injector.
- Funciona bien con la sintaxis de inyección de la matriz angular, que es esencial si su javascript va a ser minimizado.
- Puede agregar fácilmente servicios inyectables adicionales al controlador base, sin tener que recordar agregarlos y pasarlos a través de todos sus controladores secundarios.
Contras:
- El controlador base debe definirse como una variable que puede contaminar el alcance global. Lo he evitado en mi ejemplo de uso envolviendo todo en una función autoejecutable anónima, pero esto significa que todos los controladores secundarios deben declararse en el mismo archivo.
- Este patrón funciona bien para los controladores que se crean instancias directamente desde su html, pero no es tan bueno para los controladores que crea desde su código a través del servicio $ controller (), porque su dependencia del inyector evita que inyecte directamente, no - parámetros de servicio desde su código de llamada.
Otra buena solución tomada de este 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;
});
}]);
Para la herencia puede usar patrones de herencia de 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 sintaxis de controllerAs
(que recomiendo encarecidamente), 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 constructora "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
};
}]);
Puede crear un servicio y heredar su comportamiento en cualquier controlador simplemente inyectándolo.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert(''Hello, World!'');
};
return reusableCode;
});
Luego, en su controlador que desea extender desde el servicio de código reutilizable 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
Puede extenderse con servicios , fábricas o proveedores . son lo mismo pero con diferente grado de flexibilidad.
aquí un ejemplo usando fábrica: 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í puedes usar la función de tienda también:
<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 de JavaScript simple
Ver más detalles aquí http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
Puedes intentar 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(){
}));
Tal vez no amplíe un controlador, pero es posible extender un controlador o hacer que un único controlador sea una mezcla de múltiples 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 padre, también se ejecuta la lógica contenida en él. Consulte $ controller () para obtener más información, pero solo se debe pasar el valor de $scope
. Todos los demás valores se inyectarán normalmente.
@mwarren , su preocupación se soluciona de forma automática mediante inyección de dependencia angular. Todo lo que necesita es inyectar $ scope, aunque puede anular los otros valores inyectados si lo desea. Toma el siguiente ejemplo:
(function(angular) {
var module = angular.module(''.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=".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'', el documento $ se inyecta para nosotros.
Usted no extiende los controladores. Si realizan las mismas funciones básicas, entonces esas funciones deben moverse a un servicio. Ese servicio se puede inyectar en sus controladores.