web-dev-qa-db-fra.com

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

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

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

Quand 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 en faire un service?

94
Scottie

Si votre intention est de vous procurer le contrôleur déjà instancié d'un autre composant et que si vous suivez l'approche par composant/directive, vous pouvez toujours require un contrôleur (instance d'un composant) à partir 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 ressembler à 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>
_

Vous pouvez configurer de nombreuses façons requis.

(pas de préfixe) - Localisez le contrôleur requis sur l'élément en cours. Lancer une erreur si non trouvé.

? - 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 non trouvé.

^^ - Recherchez le contrôleur requis en recherchant les parents de l'élément. Lancer une erreur si non trouvé.

? ^ - Essayez de localiser le contrôleur requis en recherchant l’élément et ses parents ou passez null au lien fn s’il n’a pas été 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é.



Ancienne réponse:

Vous devez injecter le service $controller pour instancier un contrôleur dans un autre contrôleur. Mais sachez que cela pourrait entraîner des problèmes de conception. Vous pouvez toujours créer des services réutilisables qui suivent la 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 le _$scope_ et non sur l'instance du contrôleur.

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

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

et en consommant faire:

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

Dans le premier cas, le _$scope_ correspond réellement à votre modèle de vue, et dans le second cas, il s'agit de l'instance de contrôleur elle-même.

128
PSL

Je suggérerais que la question que vous devriez vous poser est comment injecter des services dans les contrôleurs. Les gros services avec des contrôleurs minces sont une bonne règle empirique, c’est-à-dire utilisez simplement des contrôleurs pour coller votre service/usine (avec la logique métier) dans vos vues.

Les contrôleurs reçoivent des ordures lors de modifications de route. Ainsi, par exemple, si vous utilisez des contrôleurs pour conserver la logique métier qui restitue une valeur, vous perdrez l'état sur deux pages si l'utilisateur de l'application clique sur le bouton Précédent du navigateur.

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émo de l'usine injectée dans deux contrôleurs

Aussi, je suggère d'avoir un lire ce tutoriel sur les services/usines.

33
cheekybastard

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

<div ng-controller="TestCtrl1">
    <div ng-controller="TestCtrl2">
      <!-- your code--> 
    </div> 
</div>
13
chetanpawar