Puis-je rendre une fonction disponible dans chaque contrôleur en angulaire?

191

Si j'ai une fonction utilitaire fooque je veux pouvoir appeler de n'importe où à l'intérieur de ma ng-appdéclaration. Est-il possible de le rendre globalement accessible dans la configuration de mon module ou dois-je l'ajouter à l'oscilloscope dans chaque contrôleur?

Ludwig Magnusson
la source
Je ne suis pas sûr à 100% à ce sujet, mais il y a une chance que vous puissiez également le définir sur votre module comme ceci: module.value('myFunc', function(a){return a;});puis l'injecter par son nom dans vos contrôleurs. (Si l'on veut éviter de faire un service)
user2173353
Cela signifie que je dois l'ajouter manuellement à chaque contrôleur. $ rootScope est la voie à suivre pour ce que je voulais faire il y a presque 2 ans =)
Ludwig Magnusson
D'ACCORD. :) J'utilise plus souvent des directives avec une portée isolée que des contrôleurs simples et je dois tout injecter de toute façon. J'aime le style de code modulaire que cela fournit. De plus, vous n'avez pas à vous soucier des portées parentes de quelque manière que ce soit et vous n'avez pas à rechercher beaucoup d'où viennent vos variables de portée. :)
user2173353

Réponses:

290

Vous avez essentiellement deux options, soit le définir en tant que service, soit le placer sur votre étendue racine. Je vous suggère d'en faire un service pour éviter de polluer la portée racine. Vous créez un service et le rendez disponible dans votre contrôleur comme ceci:

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
    <script type="text/javascript">
    var myApp = angular.module('myApp', []);

    myApp.factory('myService', function() {
        return {
            foo: function() {
                alert("I'm foo!");
            }
        };
    });

    myApp.controller('MainCtrl', ['$scope', 'myService', function($scope, myService) {
        $scope.callFoo = function() {
            myService.foo();
        }
    }]);
    </script>
</head>
<body ng-controller="MainCtrl">
    <button ng-click="callFoo()">Call foo</button>
</body>
</html>

Si ce n'est pas une option pour vous, vous pouvez l'ajouter à la portée racine comme ceci:

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
    <script type="text/javascript">
    var myApp = angular.module('myApp', []);

    myApp.run(function($rootScope) {
        $rootScope.globalFoo = function() {
            alert("I'm global foo!");
        };
    });

    myApp.controller('MainCtrl', ['$scope', function($scope){

    }]);
    </script>
</head>
<body ng-controller="MainCtrl">
    <button ng-click="globalFoo()">Call global foo</button>
</body>
</html>

De cette façon, tous vos modèles peuvent appeler globalFoo()sans avoir à le transmettre au modèle à partir du contrôleur.

Anders Ekdahl
la source
5
Dans la première solution, que se passe-t-il s'il y a des tonnes de foo()fonctions? Faire un $scope.callFoo()emballage pour chacun d'eux est trop de travail. Comment puis-je "attacher" toutes les fonctions d'une bibliothèque dans la portée afin qu'elle puisse être utilisée dans le modèle? J'ai une grande bibliothèque de conversion d'unités que je souhaite qu'elle soit disponible sur mon modèle.
AlexStack
3
Ma question aussi. J'ai essayé cela et cela fonctionne: vous pouvez le "joindre" en disant $scope.callFoo = myService.foo;au lieu de créer un nouveau wrapper à chaque endroit où vous voulez l'utiliser.
Fitter Man
1
Merci pour votre aide, je me demandais comment rendre disponible une fonction de changement de langue dans mon application et $ rootScope a fait le travail. Je voulais séparer le module de traduction de l'application afin de pouvoir le connecter également à d'autres applications.
Paulo Pedroso
Je suggérerais d'utiliser une valeur angulaire plutôt qu'une usine pour ce cas spécifique, sauf si vous prévoyez d'avoir plusieurs fonctions dans un service. S'il ne s'agit que d'une seule fonction, faites-en une valeur.
Nicholas Blasgen
J'ai eu l'erreur: [$ injector: uns]
Mark Thien
53

Vous pouvez également les combiner je suppose:

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
    <script type="text/javascript">
        var myApp = angular.module('myApp', []);

        myApp.factory('myService', function() {
            return {
                foo: function() {
                    alert("I'm foo!");
                }
            };
        });

        myApp.run(function($rootScope, myService) {
            $rootScope.appData = myService;
        });

        myApp.controller('MainCtrl', ['$scope', function($scope){

        }]);

    </script>
</head>
<body ng-controller="MainCtrl">
    <button ng-click="appData.foo()">Call foo</button>
</body>
</html>
ric
la source
7
Je pense que cela devrait être la bonne réponse, justifiée par la réponse de @Praym. Cela n'a pas de sens de spécifier une dépendance de service dans 10 contrôleurs différents.
jvannistelrooy
Le service peut-il inclure des méthodes / fonctions qui peuvent CRUD propriétés / variables dans le $rootScope?
jezmck
44

Bien que la première approche soit préconisée comme l'approche «angulaire», je pense que cela ajoute des frais généraux.

Considérez si je veux utiliser cette fonction myservice.foo dans 10 contrôleurs différents. Je devrai spécifier cette dépendance 'myService', puis la propriété de portée $ scope.callFoo dans les dix. Ceci est simplement une répétition et viole en quelque sorte le principe DRY.

Alors que si j'utilise l'approche $ rootScope, je ne spécifie cette fonction globale gobalFoo qu'une seule fois et elle sera disponible dans tous mes futurs contrôleurs, quel qu'en soit le nombre.

Praym
la source
5
Il peut y avoir une certaine valeur dans la «documentation» des contrôleurs où ils reçoivent cet appel de service global. Si vous étiez vous tirez l'un de vos contrôleurs dans une autre application, il serait moins clair d'où cette fonction globale vient. J'entends reconnaître votre argument cependant.
Matthew Payne
Il ne doit être placé sur l'oscilloscope que si vous devez l'appeler depuis la vue. Dans le contrôleur, vous pouvez l'appeler directement depuis le service.
mcv
10
Ceci est un commentaire pas une réponse
Elliott
La variable $ rootScope est toujours nulle lors de l'actualisation de la page dans ce cas, vous n'obtiendrez pas la fonction. C'est pourquoi il est bon d'injecter le service et d'utiliser sa référence en application.
Ehsan Hafeez
4

AngularJs a des " Services " et des " Usines " juste pour des problèmes comme le vôtre. Ceux-ci sont utilisés pour avoir quelque chose de global entre les contrôleurs, les directives, les autres services ou tout autre composant angularjs. Vous pouvez définir des fonctions, stocker des données, faire calculer des fonctions ou tout ce que vous veulent des services internes et les utiliser dans les composants AngularJs en tant que Global .like

angular.module('MyModule', [...])
  .service('MyService', ['$http', function($http){
    return {
       users: [...],
       getUserFriends: function(userId){
          return $http({
            method: 'GET',
            url: '/api/user/friends/' + userId
          });
       }
       ....
    }
  }])

si vous avez besoin de plus

En savoir plus sur les raisons pour lesquelles nous avons besoin des services et des usines AngularJs

Hazarapet Tunanyan
la source
0

Je suis un peu plus récent dans Angular mais ce que j'ai trouvé utile (et assez simple), c'est que j'ai créé un script global que je charge sur ma page avant le script local avec des variables globales auxquelles je dois accéder de toute façon sur toutes les pages. Dans ce script, j'ai créé un objet appelé "globalFunctions" et ajouté les fonctions auxquelles j'ai besoin d'accéder globalement en tant que propriétés. par exemple globalFunctions.foo = myFunc();. Ensuite, dans chaque script local, j'ai écrit $scope.globalFunctions = globalFunctions;et j'ai instantanément accès à toute fonction que j'ai ajoutée à l'objet globalFunctions dans le script global.

C'est un peu une solution de contournement et je ne suis pas sûr que cela vous aide, mais cela m'a vraiment aidé car j'avais de nombreuses fonctions et c'était difficile de les ajouter toutes à chaque page.

Izzy
la source
1
Je suis juste curieux de savoir pourquoi les votes négatifs? Je suis nouveau et j'aimerais savoir des pros.
Izzy
Cela me semble être une solution de travail. La seule chose que je recommanderais, afin de vous assurer que votre portée est suffisamment isolée, est de créer une classe utilitaire Javascript racine globale et de suspendre vos méthodes utilitaires afin de ne pas marcher accidentellement sur un autre nom de fonction dans le vaste mer de choses injectées par Angular.
JE Carter II
Une chose à noter, et peut-être pourquoi cela est décliné, vous ne pouvez utiliser que ces fonctions dans vos modèles, pas vos modules .ts car vos appels de fonction ne résoudraient pas au moment de la compilation. C'est la raison pour laquelle on procède de manière "angulaire". Mais, si vous souhaitez simplement ajouter des décorateurs et autres à vos modèles, un fichier utilitaire global est simple et parfait.
JE Carter II