Un contrôleur AngularJS peut-il en appeler un autre?

est-il possible qu'un contrôleur utilise un autre contrôleur?

par exemple:

ce document HTML imprime simplement un message livré par le contrôleur MessageCtrl dans le fichier messageCtrl.js .

<html xmlns:ng="http://angularjs.org/">
<head>
    <meta charset="utf-8" />
    <title>Inter Controller Communication</title>
</head>
<body>
    <div ng:controller="MessageCtrl">
        <p>{{message}}</p>
    </div>

    <!-- Angular Scripts -->
    <script src="http://code.angularjs.org/angular-0.9.19.js" ng:autobind></script>
    <script src="js/messageCtrl.js" type="text/javascript"></script>
</body>
</html>

le fichier du contrôleur contient le code suivant:

function MessageCtrl()
{
    this.message = function() { 
        return "The current date is: " + new Date().toString(); 
    };
}

qui imprime simplement la date courante;

si je devais ajouter un autre contrôleur, DateCtrl qui a remis la date dans un format spécifique à MessageCtrl , comment ferait-on cela? Le cadre de L'ai semble porter sur XmlHttpRequests et l'accès aux services.

554
demandé sur Quinto 2012-02-15 16:31:20

13 réponses

il y a plusieurs façons de communiquer entre les contrôleurs.

le meilleur partage probablement un service:

function FirstController(someDataService) 
{
  // use the data service, bind to template...
  // or call methods on someDataService to send a request to server
}

function SecondController(someDataService) 
{
  // has a reference to the same instance of the service
  // so if the service updates state for example, this controller knows about it
}

une autre voie émet un événement sur scope:

function FirstController($scope) 
{
  $scope.$on('someEvent', function(event, args) {});
  // another controller or even directive
}

function SecondController($scope) 
{
  $scope.$emit('someEvent', args);
}

Dans les deux cas, vous pouvez communiquer avec n'importe quel directive.

684
répondu Vojta 2014-10-22 13:11:58

voir ce violon: http://jsfiddle.net/simpulton/XqDxG /

regardez aussi la vidéo suivante: communiquer entre les contrôleurs

Html:

<div ng-controller="ControllerZero">
  <input ng-model="message" >
  <button ng-click="handleClick(message);">LOG</button>
</div>

<div ng-controller="ControllerOne">
  <input ng-model="message" >
</div>

<div ng-controller="ControllerTwo">
  <input ng-model="message" >
</div>

javascript:

var myModule = angular.module('myModule', []);
myModule.factory('mySharedService', function($rootScope) {
  var sharedService = {};

  sharedService.message = '';

  sharedService.prepForBroadcast = function(msg) {
    this.message = msg;
    this.broadcastItem();
  };

  sharedService.broadcastItem = function() {
    $rootScope.$broadcast('handleBroadcast');
  };

  return sharedService;
});

function ControllerZero($scope, sharedService) {
  $scope.handleClick = function(msg) {
    sharedService.prepForBroadcast(msg);
  };

  $scope.$on('handleBroadcast', function() {
    $scope.message = sharedService.message;
  });        
}

function ControllerOne($scope, sharedService) {
  $scope.$on('handleBroadcast', function() {
    $scope.message = 'ONE: ' + sharedService.message;
  });        
}

function ControllerTwo($scope, sharedService) {
  $scope.$on('handleBroadcast', function() {
    $scope.message = 'TWO: ' + sharedService.message;
  });
}

ControllerZero.$inject = ['$scope', 'mySharedService'];        

ControllerOne.$inject = ['$scope', 'mySharedService'];

ControllerTwo.$inject = ['$scope', 'mySharedService'];
119
répondu adardesign 2013-07-20 23:12:49

voici un exemple d'une page de deux contrôleurs partageant des données de service:

<!doctype html>
<html ng-app="project">
<head>
    <title>Angular: Service example</title>
    <script src="http://code.angularjs.org/angular-1.0.1.js"></script>
    <script>
var projectModule = angular.module('project',[]);

projectModule.factory('theService', function() {  
    return {
        thing : {
            x : 100
        }
    };
});

function FirstCtrl($scope, theService) {
    $scope.thing = theService.thing;
    $scope.name = "First Controller";
}

function SecondCtrl($scope, theService) {   
    $scope.someThing = theService.thing; 
    $scope.name = "Second Controller!";
}
    </script>
</head>
<body>  
    <div ng-controller="FirstCtrl">
        <h2>{{name}}</h2>
        <input ng-model="thing.x"/>         
    </div>

    <div ng-controller="SecondCtrl">
        <h2>{{name}}</h2>
        <input ng-model="someThing.x"/>             
    </div>
</body>
</html>

aussi ici: https://gist.github.com/3595424

52
répondu exclsr 2012-09-02 06:51:53

si vous voulez appeler un contrôleur dans un autre il y a quatre méthodes disponibles

  1. $ rootScope.$emit () et $ rootScope.$ broadcast()
  2. si le second contrôleur est enfant ,vous pouvez utiliser la communication Parent-enfant .
  3. De L'Utilisation Des Services
  4. sorte de hack - avec l'aide d'angular.element ()

1. $rootScope.$émettre() et $ rootScope.$ broadcast()

contrôleur et sa portée peuvent être détruits, mais le $ rootScope reste dans l'application, c'est pourquoi nous prenons $rootScope parce que $rootScope est le parent de tous les scopes .

si vous effectuez la communication de parent à enfant et même enfant veut communiquer avec ses frères et sœurs, vous pouvez utiliser $ broadcast

si vous effectuez une communication de l'enfant à parent, pas de fratrie invovled alors vous pouvez utiliser $rootScope.$émettent des 151980920"

HTML

<body ng-app="myApp">
    <div ng-controller="ParentCtrl" class="ng-scope">
      // ParentCtrl
      <div ng-controller="Sibling1" class="ng-scope">
        // Sibling first controller
      </div>
      <div ng-controller="Sibling2" class="ng-scope">
        // Sibling Second controller
        <div ng-controller="Child" class="ng-scope">
          // Child controller
        </div>
      </div>
    </div>
</body>

Angularjs Code

 var app =  angular.module('myApp',[]);//We will use it throughout the example 
    app.controller('Child', function($rootScope) {
      $rootScope.$emit('childEmit', 'Child calling parent');
      $rootScope.$broadcast('siblingAndParent');
    });

app.controller('Sibling1', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside Sibling one');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

app.controller('Sibling2', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside Sibling two');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

app.controller('ParentCtrl', function($rootScope) {
  $rootScope.$on('childEmit', function(event, data) {
    console.log(data + ' Inside parent controller');
  });
  $rootScope.$on('siblingAndParent', function(event, data) {
    console.log('broadcast from child in parent');
  });
});

dans la console de code ci-dessus de $emit 'childEmit' n'appellera pas inside child Brothers et il appellera inside only parent, où $ broadcast sera aussi appelé inside brothers and parent.C'est l'endroit où la performance entre en action.$émettent est préférable, si vous utilisez de l'enfant à la communication avec les parents parce qu'il ignore certains sale contrôles.

2. Si le second contrôleur est enfant, vous pouvez utiliser la communication parent enfant

C'est l'une des meilleures méthodes, Si vous voulez faire communication de parent d'enfant où l'enfant veut communiquer avec parent immédiat alors il ne serait pas nécessaire de $ diffusion ou $émission mais si vous voulez faire la communication de parent à enfant alors vous devez utiliser l'un ou l'autre service ou $ broadcast

par exemple HTML: -

<div ng-controller="ParentCtrl">
 <div ng-controller="ChildCtrl">
 </div>
</div>

Angularjs

 app.controller('ParentCtrl', function($scope) {
   $scope.value='Its parent';
      });
  app.controller('ChildCtrl', function($scope) {
   console.log($scope.value);
  });

chaque fois que vous utilisez la communication enfant-parent, Angularjs recherchera une variable à l'intérieur de l'enfant, si elle n'est pas présente à l'intérieur, elle choisira de voir les valeurs à l'intérieur du contrôleur parent.

3.Utiliser Les Services De

AngularJS supporte les concepts de "Seperation of Concerns" using services architecture. Les Services sont des fonctions javascript et sont responsables de faire une tâche spécifique seulement.Cela fait d'eux une entité individuelle qui est maintenable et testable .Services utilisés pour injecter en utilisant le mécahnisme de L'Injection de dépendance des Angularjs.

Angularjs code:

app.service('communicate',function(){
  this.communicateValue='Hello';
});

app.controller('ParentCtrl',function(communicate){//Dependency Injection
  console.log(communicate.communicateValue+" Parent World");
});

app.controller('ChildCtrl',function(communicate){//Dependency Injection
  console.log(communicate.communicateValue+" Child World");
});

il donnera sortie Hello Child World et Hello Parent World . Selon les documents angulaires des services Singletons-chaque composant dépendant d'un service obtient une référence à l'instance unique générée par l'usine de service .

4.Genre de hack - avec l'aide de anguleux.element ()

cette méthode obtient scope () de l'élément par son Id / unique classe.anguleux.element() la méthode retourne element et scope () donne $scope variable d'une autre variable en utilisant $scope variable d'un controller à l'intérieur d'un autre n'est pas une bonne pratique.

HTML: -

<div id='parent' ng-controller='ParentCtrl'>{{varParent}}
 <span ng-click='getValueFromChild()'>Click to get ValueFormChild</span>
 <div id='child' ng-controller='childCtrl'>{{varChild}}
   <span ng-click='getValueFromParent()'>Click to get ValueFormParent </span>
 </div>
</div>

Angularjs: -

app.controller('ParentCtrl',function($scope){
 $scope.varParent="Hello Parent";
  $scope.getValueFromChild=function(){
  var childScope=angular.element('#child').scope();
  console.log(childScope.varChild);
  }
});

app.controller('ChildCtrl',function($scope){
 $scope.varChild="Hello Child";
  $scope.getValueFromParent=function(){
  var parentScope=angular.element('#parent').scope();
  console.log(parentScope.varParent);
  }
}); 

dans les contrôleurs de code ci-dessus montrent leur propre valeur sur Html et quand vous cliquerez sur le texte vous obtiendrez des valeurs dans la console en conséquence.Si vous cliquez sur la portée des contrôleurs parent, le navigateur va consoler la valeur de child et viceversa.

47
répondu Shubham Nigam 2017-01-25 13:36:43

si vous cherchez à émettre et diffuser des événements pour partager des données ou des fonctions d'appel à travers les contrôleurs , s'il vous plaît regarder ce lien : et vérifier la réponse par zbynour (réponse avec des votes max). Je cite sa réponse !!!

si scope of firstCtrl est parent du scope secondCtrl, votre code devrait fonctionner en remplaçant $emit par $broadcast dans firstCtrl:

function firstCtrl($scope){
    $scope.$broadcast('someEvent', [1,2,3]);
}

function secondCtrl($scope){
    $scope.$on('someEvent', function(event, mass) {console.log(mass)});
}

s'il n'y a pas de relation parent-enfant entre vos lunettes, vous pouvez injecter $rootScope dans le contrôleur et diffuser l'événement à toutes les lunettes d'enfant (c.-à-d. aussi secondCtrl).

function firstCtrl($rootScope){
    $rootScope.$broadcast('someEvent', [1,2,3]);
}

enfin, lorsque vous avez besoin d'envoyer l'événement depuis le contrôleur enfant vers le haut, vous pouvez utiliser $scope.$émettre. Si le champ d'application de firstCtrl est le parent du champ d'application de secondCtrl:

function firstCtrl($scope){
    $scope.$on('someEvent', function(event, data) { console.log(data); });
}

function secondCtrl($scope){
    $scope.$emit('someEvent', [1,2,3]);
}
31
répondu SharpCoder 2017-05-23 12:02:45

Deux violons: (Non approche de service)

1) pour contrôleur Parent - enfant - utilisant $scope de contrôleur parent pour émettre/diffuser des événements. http://jsfiddle.net/laan_sachin/jnj6y /

2) utilisant $rootScope pour des contrôleurs non liés. http://jsfiddle.net/VxafF /

24
répondu DarkKnight 2012-10-07 17:10:49

réellement en utilisant emit et broadcast est inefficace parce que l'événement bulles de haut en bas de la hiérarchie de portée qui peut facilement se dégrader en performance bottlement pour une application complexe.

je suggère d'utiliser un service. Voici comment je l'ai récemment mis en œuvre dans un de mes projets - https://gist.github.com/3384419 .

idée de base-enregistrer un bus pub-sous/événement comme un service. Puis injectez ce bus d ' événement où jamais vous avez besoin de vous abonner ou de publier des événements et sujets.

16
répondu numan salati 2017-07-04 16:53:19

je connais aussi ce chemin.

angular.element($('#__userProfile')).scope().close();

mais je ne l'utilise pas trop, parce que je n'aime pas utiliser les sélecteurs jQuery en code angulaire.

3
répondu Andrey Korchak 2013-10-04 21:25:54

je ne sais pas si c'est hors normes, mais si vous avez tous vos contrôleurs sur le même fichier, puis vous pouvez faire quelque chose comme ceci:

app = angular.module('dashboardBuzzAdmin', ['ngResource', 'ui.bootstrap']);

var indicatorsCtrl;
var perdiosCtrl;
var finesCtrl;

app.controller('IndicatorsCtrl', ['$scope', '$http', function ($scope, $http) {
  indicatorsCtrl = this;
  this.updateCharts = function () {
    finesCtrl.updateChart();
    periodsCtrl.updateChart();
  };
}]);

app.controller('periodsCtrl', ['$scope', '$http', function ($scope, $http) {
  periodsCtrl = this;
  this.updateChart = function() {...}
}]);

app.controller('FinesCtrl', ['$scope', '$http', function ($scope, $http) {
  finesCtrl = this;
  this.updateChart = function() {...}
}]);

comme vous pouvez le voir indicateurscrtrl appelle les fonctions updateChart des deux autres contrôleurs lors de l'appel de updateCharts.

3
répondu tomascharad 2014-10-20 14:41:13

il existe une méthode qui ne dépend pas des services, $broadcast ou $emit . Ce n'est pas approprié dans tous les cas, mais si vous avez 2 controllers liés qui peuvent être résumés en directives, alors vous pouvez utiliser l'option require dans la définition de la directive. C'est très probablement la façon dont ngModel et ngForm communiquent. Vous pouvez utiliser ceci pour communiquer entre les contrôleurs de directive qui sont soit imbriqués, soit sur le même élément.

pour une situation parent/enfant, l'utilisation serait la suivante:

<div parent-directive>
  <div inner-directive></div>
</div>

et les principaux points pour le faire fonctionner: sur la directive parent, avec les méthodes à appeler, vous devez les définir sur this (pas sur $scope ):

controller: function($scope) {
  this.publicMethodOnParentDirective = function() {
    // Do something
  }
}

sur la définition de la directive child, vous pouvez utiliser l'option require pour que le contrôleur parent passe à la fonction link (vous pouvez alors appeler les fonctions à partir de la scope de la directive child).

require: '^parentDirective',
template: '<span ng-click="onClick()">Click on this to call parent directive</span>',
link: function link(scope, iElement, iAttrs, parentController) {
  scope.onClick = function() {
    parentController.publicMethodOnParentDirective();
  }
}

ci-dessus peut être vu à http://plnkr.co/edit/poeq460VmQER8Gl9w8Oz?p=preview

une directive frère est utilisée de la même manière, mais les deux directives sur le même élément:

<div directive1 directive2>
</div>

utilisé en créant une méthode sur directive1 :

controller: function($scope) {
  this.publicMethod = function() {
    // Do something
  }
}

et dans directive2 cela peut être appelé en utilisant l'option require qui résulte en siblingController passe à la fonction link:

require: 'directive1',
template: '<span ng-click="onClick()">Click on this to call sibling directive1</span>',
link: function link(scope, iElement, iAttrs, siblingController) {
  scope.onClick = function() {
    siblingController.publicMethod();
  }
}

cela peut être vu à http://plnkr.co/edit/MUD2snf9zvadfnDXq85w?p=preview .

à quoi ça sert?

  • Parent: tout cas où les éléments de l'enfant doivent "s'enregistrer" auprès d'un parent. Un peu comme la relation entre ngModel et ngForm. Ces pouvez ajouter certains comportements qui peuvent affecte les modèles. Vous pourriez aussi avoir quelque chose de purement DOM, où un élément parent doit gérer les positions de certains enfants, par exemple gérer ou réagir au scrolling.

  • fratrie: permettre à une directive de modifier son comportement. ngModel est le cas classique, pour ajouter des parsers / validation à l'utilisation de ngModel sur les entrées.

2
répondu Michal Charemza 2013-12-27 13:16:15

vous pouvez injecter le service '$ controller' dans votre contrôleur parent (MessageCtrl) et ensuite instancier / injecter le contrôleur enfant(DateCtrl) en utilisant:

$scope.childController = $controller('childController', { $scope: $scope.$new() });

Maintenant vous pouvez accéder aux données de votre contrôleur enfant en appelant ses méthodes car il s'agit d'un service.

Laissez-moi savoir si n'importe quelle question.

2
répondu Smrutiranjan Sahu 2015-04-16 18:56:12

la suite est une publish-subscribe approche qui est indépendamment de JS angulaire.

Recherche Param Contrôleur

//Note: Multiple entities publish the same event
regionButtonClicked: function () 
{
        EM.fireEvent('onSearchParamSelectedEvent', 'region');
},

plantButtonClicked: function () 
{
        EM.fireEvent('onSearchParamSelectedEvent', 'plant');
},

Recherche Choix Contrôleur

//Note: It subscribes for the 'onSearchParamSelectedEvent' published by the Search Param Controller
localSubscribe: function () {
        EM.on('onSearchParamSelectedEvent', this.loadChoicesView, this);

});


loadChoicesView: function (e) {

        //Get the entity name from eData attribute which was set in the event manager
        var entity = $(e.target).attr('eData');

        console.log(entity);

        currentSelectedEntity = entity;
        if (entity == 'region') {
            $('.getvalue').hide();
            this.loadRegionsView();
            this.collapseEntities();
        }
        else if (entity == 'plant') {
            $('.getvalue').hide();
            this.loadPlantsView();
            this.collapseEntities();
        }


});

Event Manager

myBase.EventManager = {

    eventArray:new Array(),


    on: function(event, handler, exchangeId) {
        var idArray;
        if (this.eventArray[event] == null) {
            idArray = new Array();
        } else { 
            idArray = this.eventArray[event];
        }
        idArray.push(exchangeId);
        this.eventArray[event] = idArray;

        //Binding using jQuery
        $(exchangeId).bind(event, handler);
    },

    un: function(event, handler, exchangeId) {

        if (this.eventArray[event] != null) {
            var idArray = this.eventArray[event];
            idArray.pop(exchangeId);
            this.eventArray[event] = idArray;

            $(exchangeId).unbind(event, handler);
        }
    },

    fireEvent: function(event, info) {
        var ids = this.eventArray[event];

        for (idindex = 0; idindex < ids.length; idindex++) {
            if (ids[idindex]) {

                //Add attribute eData
                $(ids[idindex]).attr('eData', info);
                $(ids[idindex]).trigger(event);
            }
        }
    }
};

Global

var EM = myBase.EventManager;
1
répondu Lijo 2014-02-21 14:10:28

en angle 1.5 ceci peut être accompli en faisant ce qui suit:

(function() {
  'use strict';

  angular
    .module('app')
    .component('parentComponent',{
      bindings: {},
      templateUrl: '/templates/products/product.html',
      controller: 'ProductCtrl as vm'
    });

  angular
    .module('app')
    .controller('ProductCtrl', ProductCtrl);

  function ProductCtrl() {
    var vm = this;
    vm.openAccordion = false;

    // Capture stuff from each of the product forms
    vm.productForms = [{}];

    vm.addNewForm = function() {
      vm.productForms.push({});
    }
  }

}());

C'est le composant parent. En cela, j'ai créé une fonction qui pousse un autre objet dans mon productForms tableau - note - c'est juste mon exemple, cette fonction peut être n'importe quoi, vraiment.

maintenant nous pouvons créer un autre composant qui fera usage de require :

(function() {
  'use strict';

  angular
    .module('app')
    .component('childComponent', {
      bindings: {},
      require: {
        parent: '^parentComponent'
      },
      templateUrl: '/templates/products/product-form.html',
      controller: 'ProductFormCtrl as vm'
    });

  angular
    .module('app')
    .controller('ProductFormCtrl', ProductFormCtrl);

  function ProductFormCtrl() {
    var vm = this;

    // Initialization - make use of the parent controllers function
    vm.$onInit = function() {
      vm.addNewForm = vm.parent.addNewForm;
    };  
  }

}());

ici le composant enfant crée un référence à la fonction parent component addNewForm qui peut alors être liée au HTML et appelée comme toute autre fonction.

1
répondu Katana24 2016-03-23 17:10:13