Posso rendere disponibile una funzione in ogni controller in angolare?


191

Se ho una funzione di utilità fooche voglio poter chiamare da qualsiasi parte della mia ng-appdichiarazione. Esiste un modo per renderlo accessibile a livello globale nella configurazione del mio modulo o devo aggiungerlo all'ambito in ogni controller?


Non ne sono sicuro al 100%, ma c'è una possibilità che tu possa anche definirlo sul tuo modulo in questo modo: module.value('myFunc', function(a){return a;});e quindi iniettarlo per nome nei tuoi controller. (Se si vuole evitare di effettuare un servizio)
user2173353

Ciò significa che devo aggiungerlo manualmente a tutti i controller. $ rootScope è la strada da percorrere per quello che volevo fare quasi 2 anni fa =)
Ludwig Magnusson,

OK. :) Uso solo le direttive con ambito isolato più spesso dei semplici controller e devo comunque iniettare tutto. Mi piace lo stile di codice modulare che questo fornisce. Inoltre, non devi fare confusione con gli ambiti padre in alcun modo e non devi cercare molto da dove provengono le variabili dell'ambito. :)
user2173353,

Risposte:


290

Fondamentalmente hai due opzioni, o definirlo come un servizio o posizionarlo sul tuo ambito di root. Suggerirei di crearne un servizio per evitare di inquinare l'ambito di root. Si crea un servizio e lo si rende disponibile nel proprio controller in questo modo:

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

Se questa non è un'opzione per te, puoi aggiungerla all'ambito radice in questo modo:

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

In questo modo, tutti i tuoi modelli possono chiamare globalFoo()senza dover passare al modello dal controller.


5
Nella prima soluzione, cosa succede se ci sono tonnellate di foo()funzioni? Realizzare un $scope.callFoo()wrapper per ognuno di essi è troppo lavoro. Come posso "collegare" tutte le funzioni di una libreria nell'ambito in modo che possa essere utilizzato nel modello? Ho una libreria di conversione di unità di grandi dimensioni che voglio che sia disponibile sul mio modello.
AlexStack,

3
Anche la mia domanda. L'ho provato e funziona: puoi "collegarlo" dicendo $scope.callFoo = myService.foo;invece di creare un nuovo wrapper in ogni luogo in cui desideri utilizzarlo.
Fitter Man,

1
Grazie per il tuo aiuto, mi chiedevo come rendere disponibile una funzione di cambio lingua in tutta la mia app e $ rootScope ha fatto il lavoro. Volevo mantenere il modulo di traduzione separato dall'applicazione in modo da poterlo collegare anche ad altre app.
Paulo Pedroso,

Suggerirei di utilizzare un valore angolare piuttosto che una fabbrica per questo caso specifico a meno che non preveda di avere più funzioni all'interno di un servizio. Se è solo una funzione, rendila un valore.
Nicholas Blasgen,

Ho ricevuto l'errore: [$ injector: unpr]
Mark Thien il

53

Puoi anche combinarli immagino:

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

7
Penso che questa dovrebbe essere la risposta corretta, giustificata dalla risposta di @Praym. Non ha senso specificare una dipendenza del servizio in 10 controller diversi.
jvannistelrooy,

Il servizio può includere metodi / funzioni che possono proprietà / variabili CRUD nel $rootScope?
jezmck,

44

Sebbene il primo approccio sia sostenuto come "l'approccio angolare", ritengo che ciò aggiunga spese generali.

Considera se voglio usare questa funzione myservice.foo in 10 controller diversi. Dovrò specificare questa dipendenza 'myService' e quindi la proprietà scope $ scope.callFoo in tutte e dieci. Questa è semplicemente una ripetizione e in qualche modo viola il principio DRY.

Considerando che, se utilizzo l'approccio $ rootScope, specifico questa funzione globale gobalFoo solo una volta e sarà disponibile in tutti i miei controller futuri, indipendentemente da quanti.


5
Potrebbe esserci del valore nella "documentazione" dei controller da cui ottengono quella chiamata di servizio globale. Se tu fossi uno dei tuoi controller in un'altra applicazione sarebbe meno chiaro da dove provenga quella funzione globale. Ho sentito riconoscere il tuo argomento però.
Matthew Payne,

Deve essere inserito nell'ambito solo se è necessario chiamarlo dalla vista. Nel controller, puoi chiamarlo direttamente dal servizio.
mcv,

10
Questo è un commento non una risposta
Elliott il

La variabile $ rootScope si annulla sempre all'aggiornamento della pagina in quel caso non otterrai la funzione. Ecco perché è buono iniettare il servizio e usare il suo riferimento nell'applicazione.
Ehsan Hafeez,

4

AngularJs ha " Servizi " e " Fabbriche " solo per problemi come i tuoi. Questi sono usati per avere qualcosa di globale tra Controllori, Direttive, Altri Servizi o qualsiasi altro componente angularjs. Puoi definire funzioni, archiviare dati, fare funzioni di calcolo o qualunque cosa tu desidera all'interno dei Servizi e utilizzarli nei Componenti di AngularJs come Global .like

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

se hai bisogno di più

Scopri di più sul perché abbiamo bisogno dei servizi e delle fabbriche di AngularJs


0

Sono un po 'più nuovo di Angular ma quello che ho trovato utile da fare (e piuttosto semplice) è che ho creato uno script globale che carico sulla mia pagina prima dello script locale con variabili globali a cui devo comunque accedere su tutte le pagine. In quello script, ho creato un oggetto chiamato "globalFunctions" e ho aggiunto le funzioni di cui ho bisogno per accedere a livello globale come proprietà. es globalFunctions.foo = myFunc();. Quindi, in ogni script locale, ho scritto $scope.globalFunctions = globalFunctions;e ho immediatamente accesso a qualsiasi funzione che ho aggiunto all'oggetto globalFunctions nello script globale.

Questo è un po 'una soluzione alternativa e non sono sicuro che ti aiuti, ma sicuramente mi ha aiutato dato che avevo molte funzioni ed è stato un dolore aggiungerle tutte ad ogni pagina.


1
Sono solo curioso di sapere perché i downvotes? Sono nuovo e vorrei sapere dai professionisti.
Izzy,

Mi sembra una soluzione funzionante. L'unica cosa che suggerirei, al fine di assicurarmi che il tuo ambito di applicazione sia sufficientemente isolato, è creare una classe di utilità Javascript globale radice e sospenderne i metodi di utilità in modo che non passi accidentalmente su un altro nome di funzione nella vasto mare di cose iniettate da Angular.
JE Carter II

Una cosa da notare, e forse perché questo è downvoted, potresti usare solo quelle funzioni nei tuoi template, non i tuoi moduli .ts poiché le tue chiamate di funzione non si risolverebbero al momento della compilazione. Questa è la ragione per farlo nel modo "angolare". Ma, se vuoi solo aggiungere decoratori e simili ai tuoi modelli, un file di utilità globale è semplice e perfetto.
JE Carter II
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.