Comment injecter un contrôleur dans un autre contrôleur dans AngularJS

Je suis nouveau à Angular et j'essaie de comprendre comment faire les choses...

En utilisant AngularJS, Comment puis-je injecter un contrôleur à utiliser dans un autre contrôleur?

J'ai l'extrait suivant:

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

Lorsque j'exécute ceci, j'obtiens l'erreur:

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

Devrais-je même essayer d'utiliser un contrôleur à l'intérieur d'un autre contrôleur, ou devrais-je rendre ce service?

94
demandé sur PSL 2014-08-21 05:58:28

7 réponses

Si votre intention est de mettre la main sur un contrôleur déjà instancié d'un autre composant et que si vous suivez une approche basée sur un composant/une directive, vous pouvez toujours require un contrôleur (instance d'un composant) d'un autre composant qui suit une certaine hiérarchie.

Par exemple:

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

Maintenant l'utilisation de ces composants ci-dessus pourrait être quelque chose comme ceci:

<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>

Il y a plusieurs façons de configurer besoin.

(Pas de préfixe) - localisez le contrôleur requis sur l'élément courant. Lancer une erreur si elle n'est pas trouvée.

? - Essayez de localiser le contrôleur requis ou passez null au lien fn s'il n'est pas trouvé.

^ - localisez le contrôleur requis en recherchant l'élément et ses parents. Lancer une erreur si elle n'est pas trouvée.

^^ - recherchez le contrôleur requis en recherchant les parents de l'élément. Lever une erreur si pas trouver.

?^ - Essayez de localiser le contrôleur requis en recherchant l'élément et ses parents ou passez null au lien fn s'il n'est pas trouvé.

?^ ^ - Essayez de localiser le contrôleur requis en recherchant les parents de l'élément, ou passez null au lien fn s'il n'est pas trouvé.



Vieille Réponse:

, Vous devez injecter $controller service d'instancier un contrôleur à l'intérieur d'un autre contrôleur. Mais sachez que cela pourrait conduire à certains problèmes de conception. Vous pouvez toujours créer des services réutilisables qui suivent une responsabilité unique et les injecter dans les contrôleurs selon vos besoins.

Exemple:

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

Dans tous les cas, vous ne pouvez pas appeler TestCtrl1.myMethod() car vous avez attaché la méthode sur $scope et non sur l'instance du contrôleur.

Si vous partagez le contrôleur, alors il serait toujours préférable de faire: -

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

Et tout en consommant faire:

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

Dans le premier cas vraiment le $scope est votre modèle de vue, et dans le second cas c'est l'instance du contrôleur elle-même.

129
répondu PSL 2016-08-25 03:13:08

Je suggère que la question que vous devriez poser est de savoir comment injecter des services dans les contrôleurs. Fat services avec des contrôleurs maigres est une bonne règle de base, aka il suffit d'utiliser des contrôleurs pour coller votre service/usine (avec la logique métier) dans vos vues.

Les contrôleurs sont collectés lors des modifications d'itinéraire, par exemple, si vous utilisez des contrôleurs pour contenir la logique métier qui rend une valeur, votre état va perdre sur deux pages si l'utilisateur de l'application clique sur le navigateur bouton.

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

Voici un travail démonstration de l'usine injecté dans deux contrôleurs

Aussi, je suggère d'avoir une lecture de ce tutoriel sur les services / usines.

33
répondu cheekybastard 2017-05-12 08:59:03

Il n'est pas nécessaire d'importer / injecter votre contrôleur dans JS. Vous pouvez simplement injecter votre contrôleur / contrôleur imbriqué via votre HTML.It ça a marché pour moi. Comme:

<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>
12
répondu chetanpawar 2015-05-26 06:53:07
<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>

Cela fonctionne mieux dans mon cas, où TestCtrl2 a ses propres directives.

var testCtrl2 = $controller('TestCtrl2')

Cela me donne une erreur en disant scopeProvider erreur d'injection.

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

Cela ne fonctionne pas vraiment si vous avez des directives dans 'TestCtrl1', cette directive a en fait une portée différente de celle créée ici. Vous vous retrouvez avec deux instances de 'TestCtrl1'.

-1
répondu binRAIN 2015-07-09 02:44:52

La meilleure solution:-

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

/ / Ici, vous avez reçu le premier appel du contrôleur sans l'exécuter

-1
répondu Atul Singh 2016-08-27 09:54:44

Vous pouvez également utiliser $rootScope pour appeler une fonction / méthode du 1er contrôleur à partir du deuxième contrôleur comme ceci,

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

.controller('ctrl2', function($rootScope, $scope) {
     $rootScope.methodOf2ndCtrl = function() {
     //Your code here. 
}
})
-1
répondu user5943763 2016-08-31 06:31:25

Utilisez typescript pour votre codage, car il est orienté objet, strictement typé et facile à maintenir le code ...

Pour plus d'informations sur typescipt cliquez ici

Voici un exemple simple que j'ai créé pour partager des données entre deux contrôleurs en utilisant 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);

}

-2
répondu UniCoder 2016-09-15 12:07:56