Czy mogę udostępnić funkcję w każdym kontrolerze kątowym?

191

Jeśli mam funkcję narzędzia foo, do której chcę zadzwonić z dowolnego miejsca w mojej ng-appdeklaracji. Czy jest jakiś sposób, że mogę uczynić go globalnie dostępnym w mojej konfiguracji modułu, czy muszę dodać go do zakresu w każdym kontrolerze?

Ludwig Magnusson
źródło
Nie jestem tego w 100% pewien, ale istnieje szansa, że ​​możesz również zdefiniować go w swoim module w następujący sposób: module.value('myFunc', function(a){return a;});a następnie wstrzyknąć go z nazwy do kontrolerów. (Jeśli ktoś chce uniknąć świadczenia usługi)
użytkownik2173353
Oznacza to, że muszę dodać go ręcznie do każdego kontrolera. $ rootScope jest drogą do tego, co chciałem zrobić prawie 2 lata temu =)
Ludwig Magnusson
DOBRZE. :) Po prostu używam dyrektyw z izolowanym zakresem częściej niż zwykłe kontrolery i i tak muszę wszystko wstrzykiwać. Podoba mi się ten modułowy styl kodu. Ponadto nie musisz w żaden sposób zadzierać z zasięgami nadrzędnymi i nie musisz dużo szukać, skąd pochodzą zmienne zakresu. :)
user2173353

Odpowiedzi:

290

Zasadniczo masz dwie opcje: albo zdefiniuj ją jako usługę, albo umieść w swoim głównym katalogu. Sugerowałbym, aby zrobić z niego usługę, aby uniknąć zanieczyszczenia zakresu głównego. Tworzysz usługę i udostępniasz ją w kontrolerze w następujący sposób:

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

Jeśli nie jest to dla ciebie opcja, możesz dodać ją do zakresu głównego w następujący sposób:

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

W ten sposób wszystkie twoje szablony mogą wywoływać globalFoo()bez konieczności przekazywania go do szablonu z kontrolera.

Anders Ekdahl
źródło
5
Co w pierwszym rozwiązaniu, jeśli jest mnóstwo foo()funkcji? Wykonanie $scope.callFoo()opakowania dla każdego z nich to zbyt wiele pracy. Jak mogę „dołączyć” wszystkie funkcje biblioteki do zakresu, aby można było jej użyć w szablonie? Mam dużą bibliotekę konwersji jednostek, która ma być dostępna w moim szablonie.
AlexStack,
3
Moje pytanie również. Wypróbowałem to i działa: możesz „dołączyć”, mówiąc $scope.callFoo = myService.foo;zamiast tworzyć nowe opakowanie w każdym miejscu, w którym chcesz go użyć.
Fitter Man
1
Dzięki za pomoc, zastanawiałem się, jak udostępnić funkcję zmiany języka w mojej aplikacji, a $ rootScope wykonał to zadanie. Chciałem trzymać moduł tłumaczący poza aplikacją, aby móc go również podłączyć do innych aplikacji.
Paulo Pedroso
Sugeruję użycie wartości kątowej zamiast fabryki w tym konkretnym przypadku, chyba że planujesz mieć wiele funkcji w ramach usługi. Jeśli jest to tylko jedna funkcja, uczyń ją wartością.
Nicholas Blasgen
Mam błąd: [$ injector: unpr]
Mark Thien
53

Myślę, że można je również łączyć:

<!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
źródło
7
Myślę, że powinna to być poprawna odpowiedź, uzasadniona odpowiedzią @Praym. Nie ma sensu określać zależności usługi w 10 różnych kontrolerach.
jvannistelrooy
Czy usługa może zawierać metody / funkcje, które mogą zawierać właściwości / zmienne CRUD $rootScope?
jezmck
44

Chociaż pierwsze podejście jest zalecane jako podejście „kątowe”, czuję, że powoduje to dodatkowe koszty.

Zastanów się, czy chcę użyć tej funkcji myservice.foo w 10 różnych kontrolerach. Będę musiał określić tę zależność „myService”, a następnie właściwość zakresu $ scope.callFoo we wszystkich dziesięciu. Jest to po prostu powtórzenie i w jakiś sposób narusza zasadę OSUSZANIA.

Natomiast jeśli używam metody $ rootScope, tę globalną funkcję określam tylko raz i będzie ona dostępna we wszystkich moich przyszłych kontrolerach, bez względu na to, ile z nich.

Praym
źródło
5
Dokumentacja kontrolerów może mieć pewną wartość, skąd biorą to globalne zgłoszenie serwisowe. Gdybyś był szarpnął jednego ze swoich kontrolerów do innej aplikacji, byłoby mniej jasne, skąd pochodzi ta funkcja globalna. Słyszę jednak, że rozumiem twój argument.
Matthew Payne
Musi być umieszczony na lunecie tylko wtedy, gdy trzeba wywołać go z widoku. W kontrolerze możesz zadzwonić bezpośrednio z usługi.
mcv,
10
To jest komentarz, a nie odpowiedź
Elliott
Zmienna $ rootScope zawsze ma wartość NULL podczas odświeżania strony, w takim przypadku funkcja nie będzie dostępna. Dlatego dobrze jest wstrzyknąć usługę i skorzystać z jej referencji w aplikacji.
Ehsan Hafeez
4

AngularJs ma „ Usługi ” i „ Fabryki ” tylko na takie problemy, jak twoje. Są one używane, aby mieć coś globalnego między kontrolerami, dyrektywami, innymi usługami lub innymi komponentami angularjs. Możesz definiować funkcje, przechowywać dane, wykonywać funkcje obliczeniowe lub cokolwiek innego chcą wewnątrz usług i korzystania z nich w angularjs Components jako globalnego .like

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

jeśli potrzebujesz więcej

Dowiedz się więcej o tym, dlaczego potrzebujemy usług i fabryk AngularJs

Hazarapet Tunanyan
źródło
0

Jestem trochę nowszy od Angulara, ale moim zdaniem użyteczne (i dość proste) jest to, że stworzyłem skrypt globalny, który ładuję na swoją stronę przed skryptem lokalnym ze zmiennymi globalnymi, do których i tak muszę uzyskać dostęp na wszystkich stronach. W tym skrypcie utworzyłem obiekt o nazwie „globalFunctions” i dodałem funkcje, do których muszę mieć dostęp globalnie jako właściwości. np globalFunctions.foo = myFunc();. Następnie w każdym skrypcie lokalnym pisałem $scope.globalFunctions = globalFunctions;i mam natychmiastowy dostęp do dowolnej funkcji dodanej do obiektu globalFunctions w skrypcie globalnym.

Jest to trochę obejścia i nie jestem pewien, czy ci to pomaga, ale zdecydowanie mi pomogło, ponieważ miałem wiele funkcji i dodawanie ich wszystkich na każdej stronie było uciążliwe.

Izzy
źródło
1
Jestem tylko ciekawy, dlaczego opinie negatywne? Jestem nowy i chciałbym wiedzieć od profesjonalistów.
Izzy
Wydaje mi się to działającym rozwiązaniem. Jedyną rzeczą, którą zalecałbym, aby upewnić się, że twój zakres jest wystarczająco odizolowany, jest utworzenie globalnej klasy root narzędzia JavaScript i zawieszenie na nim metod, abyś nie przypadkowo nadepnął na inną nazwę funkcji w ogromne morze rzeczy wstrzykniętych przez Angulara.
JE Carter II
Należy zwrócić uwagę na jedną rzecz i być może dlatego jest to odrzucone, możesz używać tylko tych funkcji w swoich szablonach, a nie modułów .ts, ponieważ wywołania funkcji nie zostaną rozwiązane w czasie kompilacji. To jest powód, aby robić to „kątowo”. Ale jeśli chcesz tylko dodać dekoratory i tym podobne do swoich szablonów, globalny plik narzędziowy jest prosty i w porządku.
JE Carter II