Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I inject a controller into another controller in AngularJS

I'm new to Angular and trying to figure out how to do things...

Using AngularJS, how can I inject a controller to be used within another controller?

I have the following snippet:

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(); }]); 

When I execute this, I get the error:

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

Should I even be trying to use a controller inside of another controller, or should I make this a service?

like image 944
Scottie Avatar asked Aug 21 '14 01:08

Scottie


People also ask

Can we inject one controller into another controller in AngularJS?

You can't inject controllers into one another.

Can we have two controllers in AngularJS?

Angular creates one $scope object for each controller. We also have a $rootScope accessible from every controllers.In case of multiple controllers AngularJS framework creates and pass a different $scope object to each controller so that data and methods of one controller not be accessed in another controller.

Can we call function from another controller in AngularJS?

If the two controller is nested in One controller. Then you can simply call: $scope. parentmethod();


1 Answers

If your intention is to get hold of already instantiated controller of another component and that if you are following component/directive based approach you can always require a controller (instance of a component) from a another component that follows a certain hierarchy.

For example:

//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 i.e       if(notIsValid(val)){         this.container.disableNext();       }     }  },  ...,  require : {     container: '^^wizardContainer' //Require a wizard component's controller which exist in its parent hierarchy.  },  ... }); 

Now the usage of these above components might be something like this:

<wizard-container ....> <!--some stuff--> ... <!-- some where there is this page that displays initial step via child component -->  <on-boarding-step ...>  <!--- some stuff--> </on-boarding-step> ... <!--some stuff--> </wizard-container> 

There are many ways you can set up require.

(no prefix) - Locate the required controller on the current element. Throw an error if not found.

? - Attempt to locate the required controller or pass null to the link fn if not found.

^ - Locate the required controller by searching the element and its parents. Throw an error if not found.

^^ - Locate the required controller by searching the element's parents. Throw an error if not found.

?^ - Attempt to locate the required controller by searching the element and its parents or pass null to the link fn if not found.

?^^ - Attempt to locate the required controller by searching the element's parents, or pass null to the link fn if not found.



Old Answer:

You need to inject $controller service to instantiate a controller inside another controller. But be aware that this might lead to some design issues. You could always create reusable services that follows Single Responsibility and inject them in the controllers as you need.

Example:

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. }]); 

In any case you cannot call TestCtrl1.myMethod() because you have attached the method on the $scope and not on the controller instance.

If you are sharing the controller, then it would always be better to do:-

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

and while consuming do:

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

In the first case really the $scope is your view model, and in the second case it the controller instance itself.

like image 94
PSL Avatar answered Sep 28 '22 09:09

PSL