¿Cómo inyecto un controlador en otro controlador en AngularJS

Soy nuevo en Angular e bash descubrir cómo hacer las cosas …

Usando AngularJS, ¿cómo puedo inyectar un controlador para ser utilizado dentro de otro controlador?

Tengo el siguiente fragmento:

var app = angular.module("testApp", ['']); app.controller('TestCtrl1', ['$scope', function ($scope) { $scope.myMethod = function () { console.log("TestCtrl1 - myMethod"); } }]); app.controller('TestCtrl2', ['$scope', 'TestCtrl1', function ($scope, TestCtrl1) { TestCtrl1.myMethod(); }]); 

Cuando ejecuto esto, obtengo el error:

 Error: [$injector:unpr] Unknown provider: TestCtrl1Provider <- TestCtrl1 http://errors.angularjs.org/1.2.21/$injector/unpr?p0=TestCtrl1Provider%20%3C-%20TestCtrl1 

¿Debería incluso intentar usar un controlador dentro de otro controlador, o debería hacer de esto un servicio?

Si su intención es obtener el controlador ya instanciado de otro componente y si está siguiendo un enfoque basado en componentes / directivas, siempre puede require un controlador (instancia de un componente) de otro componente que siga una cierta jerarquía.

Por ejemplo:

 //some container component that provides a wizard and transcludes the page components displayed in a wizard myModule.component('wizardContainer', { ..., controller : function WizardController() { this.disableNext = function() { //disable next step... some implementation to disable the next button hosted by the wizard } }, ... }); //some child component myModule.component('onboardingStep', { ..., controller : function OnboadingStepController(){ this.$onInit = function() { //.... you can access this.container.disableNext() function } this.onChange = function(val) { //..say some value has been changed and it is not valid i do not want wizard to enable next button so i call container's disable method ie if(notIsValid(val)){ this.container.disableNext(); } } }, ..., require : { container: '^^wizardContainer' //Require a wizard component's controller which exist in its parent hierarchy. }, ... }); 

Ahora el uso de estos componentes anteriores podría ser algo como esto:

   ...     ...   

Hay muchas formas en que puede configurar require .

(sin prefijo) – Ubique el controlador requerido en el elemento actual. Lanza un error si no lo encuentras.

? – Intentar localizar el controlador requerido o pasar nulo al enlace fn si no se encuentra.

^ – Ubique el controlador requerido buscando el elemento y sus padres. Lanza un error si no lo encuentras.

^^ – Localiza el controlador requerido buscando en los padres del elemento. Lanza un error si no lo encuentras.

? ^ – Intenta localizar el controlador requerido buscando el elemento y sus padres o pasa null al enlace fn si no se encuentra.

? ^^ – Intenta localizar el controlador requerido buscando en los padres del elemento, o pasa null al enlace fn si no se encuentra.



Vieja respuesta:

Necesita inyectar $controller servicio para instanciar un controlador dentro de otro controlador. Pero tenga en cuenta que esto podría ocasionar algunos problemas de diseño. Siempre puede crear servicios reutilizables que sigan a Single Responsibility e insertarlos en los controladores según lo necesite.

Ejemplo:

 app.controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) { var testCtrl1ViewModel = $scope.$new(); //You need to supply a scope while instantiating. //Provide the scope, you can also do $scope.$new(true) in order to create an isolated scope. //In this case it is the child scope of this scope. $controller('TestCtrl1',{$scope : testCtrl1ViewModel }); testCtrl1ViewModel.myMethod(); //And call the method on the newScope. }]); 

En cualquier caso, no puede llamar a TestCtrl1.myMethod() porque ha adjuntado el método en $scope y no en la instancia del controlador.

Si comparte el controlador, entonces siempre sería mejor hacerlo:

 .controller('TestCtrl1', ['$log', function ($log) { this.myMethod = function () { $log.debug("TestCtrl1 - myMethod"); } }]); 

y mientras consumes haz:

 .controller('TestCtrl2', ['$scope', '$controller', function ($scope, $controller) { var testCtrl1ViewModel = $controller('TestCtrl1'); testCtrl1ViewModel.myMethod(); }]); 

En el primer caso realmente el $scope es su modelo de vista, y en el segundo caso es la instancia del controlador en sí.

Sugeriría que la pregunta que debería hacerse es cómo inyectar servicios en controladores. Los servicios gordos con controladores delgados son una buena regla empírica, también usan controladores para pegar su servicio / fábrica (con la lógica comercial) en sus vistas.

Los controladores obtienen basura recolectada en cambios de ruta, por lo que, por ejemplo, si usa controladores para mantener la lógica de negocios que rinde un valor, perderá estado en dos páginas si el usuario de la aplicación hace clic en el botón Atrás del navegador.

 var app = angular.module("testApp", ['']); app.factory('methodFactory', function () { return { myMethod: function () { console.log("methodFactory - myMethod"); }; }; app.controller('TestCtrl1', ['$scope', 'methodFactory', function ($scope,methodFactory) { //Comma was missing here.Now it is corrected. $scope.mymethod1 = methodFactory.myMethod(); }]); app.controller('TestCtrl2', ['$scope', 'methodFactory', function ($scope, methodFactory) { $scope.mymethod2 = methodFactory.myMethod(); }]); 

Aquí hay una demostración funcional de fábrica inyectada en dos controladores

Además, sugiero que lean este tutorial sobre servicios / fábricas.

No es necesario importar / inyectar su controlador en JS. Simplemente puede inyectar su controlador / controlador nested a través de su HTML. Ha funcionado para mí. Me gusta :

 
 

Esto funciona mejor en mi caso, donde TestCtrl2 tiene sus propias directivas.

 var testCtrl2 = $controller('TestCtrl2') 

Esto me da un error al decir que el error de inyección de scopeProvider.

  var testCtrl1ViewModel = $scope.$new(); $controller('TestCtrl1',{$scope : testCtrl1ViewModel }); testCtrl1ViewModel.myMethod(); 

Esto realmente no funciona si tienes directivas en ‘TestCtrl1’, esa directiva en realidad tiene un scope diferente al creado aquí. Usted termina con dos instancias de ‘TestCtrl1’.

La mejor solucion:-

 angular.module("myapp").controller("frstCtrl",function($scope){$scope.name="Atul Singh";}).controller("secondCtrl",function($scope){angular.extend(this, $controller('frstCtrl', {$scope:$scope}));console.log($scope);}) 

// Aquí tienes la primera llamada del controlador sin ejecutarlo

también puede usar $rootScope para llamar a una función / método del primer controlador desde el segundo controlador como este,

 .controller('ctrl1', function($rootScope, $scope) { $rootScope.methodOf2ndCtrl(); //Your code here. }) .controller('ctrl2', function($rootScope, $scope) { $rootScope.methodOf2ndCtrl = function() { //Your code here. } }) 

use typescript para su encoding, porque está orientado a objetos, estrictamente tipado y fácil de mantener el código …

para obtener más información sobre typescipt, haga clic aquí

Aquí un ejemplo simple que he creado para compartir datos entre dos controladores usando Typescript …

 module Demo { //create only one module for single Applicaiton angular.module('app', []); //Create a searvie to share the data export class CommonService { sharedData: any; constructor() { this.sharedData = "send this data to Controller"; } } //add Service to module app angular.module('app').service('CommonService', CommonService); //Create One controller for one purpose export class FirstController { dataInCtrl1: any; //Don't forget to inject service to access data from service static $inject = ['CommonService'] constructor(private commonService: CommonService) { } public getDataFromService() { this.dataInCtrl1 = this.commonService.sharedData; } } //add controller to module app angular.module('app').controller('FirstController', FirstController); export class SecondController { dataInCtrl2: any; static $inject = ['CommonService'] constructor(private commonService: CommonService) { } public getDataFromService() { this.dataInCtrl2 = this.commonService.sharedData; } } angular.module('app').controller('SecondController', SecondController); 

}