web-dev-qa-db-fra.com

Appeler une méthode d'un contrôleur depuis un autre contrôleur en utilisant 'scope' dans AngularJS

J'essaie d'appeler une méthode de second contrôleur dans le premier contrôleur en utilisant la variable scope. Ceci est une méthode dans mon premier contrôleur:

$scope.initRestId = function(){
        var catapp = document.getElementById('SecondApp');
        var catscope = angular.element(catapp).scope();
        catscope.rest_id = $scope.user.username;
        catscope.getMainCategories();
    }; 

Je suis capable de définir la valeur de rest_id mais je ne peux pas appeler getMainCategories pour une raison quelconque. La console affiche cette erreur:

TypeError: Object # n'a pas de méthode 'getMainCategories'

Est-il possible d'appeler la méthode ci-dessus?

Edit:

J'ai utilisé l'approche suivante pour charger deux applications en même temps;

angular.bootstrap(document.getElementById('firstAppID'), ['firstApp']);
angular.bootstrap(document.getElementById('secondAppID'), ['secondApp']);

Je pourrais certainement utiliser un service ici, mais je voulais savoir s'il y avait d'autres options pour faire de même!

43
Arif Nadeem

La meilleure approche pour vous de communiquer entre les deux contrôleurs consiste à utiliser des événements.

Documentation Scope

Dans cette caisse, $on, $broadcast Et $emit.

En général, l'utilisation de angular.element(catapp).scope() a été conçue pour être utilisée en dehors des contrôleurs angular, comme dans les événements jquery.

Idéalement, dans votre utilisation, vous écrivez un événement dans le contrôleur 1 en tant que:

$scope.$on("myEvent", function (event, args) {
   $scope.rest_id = args.username;
   $scope.getMainCategories();
});

Et dans le second contrôleur vous feriez juste

$scope.initRestId = function(){
   $scope.$broadcast("myEvent", {username: $scope.user.username });
};

Edit: Réalisé, communication entre deux modules

Pouvez-vous essayer d'inclure le module firstApp en tant que dépendance du secondApp où vous déclarez le angular.module. De cette façon, vous pouvez communiquer avec l'autre application.

62

Voici une bonne démo dans Fiddle comment utiliser le service partagé dans les directives et autres contrôleurs via $scope.$on

[~ # ~] html [~ # ~]

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

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

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

<my-component ng-model="message"></my-component>

[~ # ~] js [~ # ~]

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

De la même manière, nous pouvons utiliser un service partagé dans une directive. Nous pouvons implémenter la section controller en directive et utiliser $scope.$on

myModule.directive('myComponent', function(mySharedService) {
    return {
        restrict: 'E',
        controller: function($scope, $attrs, mySharedService) {
            $scope.$on('handleBroadcast', function() {
                $scope.message = 'Directive: ' + mySharedService.message;
            });
        },
        replace: true,
        template: '<input>'
    };
});

Et voici trois de nos contrôleurs où ControllerZero a été utilisé comme déclencheur pour invoquer prepForBroadcast

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

Les ControllerOne et ControllerTwo listen message changent en utilisant $scope.$on gestionnaire.

25
Maxim Shoustin

Chaque contrôleur a ses propres portées, ce qui cause votre problème.

Avoir deux contrôleurs qui veulent accéder aux mêmes données est un signe classique que vous voulez un service . L'équipe angular recommande des contrôleurs légers qui ne font que coller entre les vues et les services. Et plus précisément, "les services doivent conserver l'état partagé entre les contrôleurs".

Heureusement, il y a une belle vidéo de 15 minutes décrivant exactement ceci (communication du contrôleur via des services): video

Misko Hevery, l'un des auteurs originaux de Angular, discute de cette recommandation (d'utiliser des services dans cette situation) dans son exposé intitulé Meilleures pratiques angulaires (passez à 28:08 pour ce sujet, bien que je recommandé de regarder tout le discours).

Vous pouvez utiliser des événements, mais ils sont conçus uniquement pour la communication entre deux parties qui souhaitent être découplées. Dans la vidéo ci-dessus, Misko explique comment ils peuvent rendre votre application plus fragile. "La plupart du temps, l'injection de services et la communication directe sont préférées et plus robustes" . (Consultez le lien ci-dessus à partir de 53h37 pour l'entendre parler de cela)

24
KayakDave