Jak Mogę dodać kilka małych funkcji użytkowych do mojej aplikacji AngularJS?

Chciałbym dodać kilka funkcji użytkowych do mojej aplikacji AngularJS. Na przykład:

$scope.isNotString = function (str) {
    return (typeof str !== "string");
}

Czy najlepszym sposobem, aby to zrobić, aby dodać je jako usługę? Z tego co przeczytałem mogę zrobić to, ale wtedy chciałbym je wykorzystać w moich stronach HTML, więc czy jest to nadal możliwe, jeśli są w służbie? Na przykład mogę użyć następującego:

 <button data-ng-click="doSomething()"
         data-ng-disabled="isNotString(abc)">Do Something
 </button>
Czy ktoś może mi podać przykład Jak mogę je dodać? Czy powinienem utworzyć usługę a może jest jakiś inny sposób. Najważniejsze I chciałby te narzędzia funkcje w pliku i nie połączone z inną częścią konfiguracji głównej. Rozumiem, że jest kilka rozwiązań, ale żadne z nich nie jest tak jasne.

Rozwiązanie 1 - zaproponowane przez Urbana

$scope.doSomething = ServiceName.functionName;
Problem w tym, że mam 20 funkcji i 10 kontrolerów. Gdybym to zrobił, oznaczałoby to dodanie dużej ilości kodu do każdego kontrolera.

Rozwiązanie 2 - zaproponowane przeze mnie

    var factory = {

        Setup: function ($scope) {

            $scope.isNotString = function (str) {
                return (typeof str !== "string");
            }

Wadą tego jest to, że na początku każdy kontroler miałbym jedno lub więcej takich wywołań konfiguracyjnych do każdej usługi, która przeszła przez $scope.

Rozwiązanie 3 - proponowane przez Urban

Zaproponowane przez Urbana rozwiązanie tworzenia ogólnej usługi wygląda dobrze. Oto moja główna konfiguracja:

var app = angular
    .module('app', ['ngAnimate', 'ui.router', 'admin', 'home', 'questions', 'ngResource', 'LocalStorageModule'])
    .config(['$locationProvider', '$sceProvider', '$stateProvider',
        function ($locationProvider, $sceProvider, $stateProvider) {

            $sceProvider.enabled(false);
            $locationProvider.html5Mode(true);

Czy powinienem dodać do tego usługę generyczną i jak Mogę to zrobić ?

 139
Author: Alan2, 2013-10-27

7 answers

Edytuj 7/1/15:

Napisałem tę odpowiedź dość dawno temu i nie nadążam za dużo z angular przez jakiś czas, ale wydaje się, że ta odpowiedź jest nadal stosunkowo popularna, więc chciałem podkreślić, że kilka z punktu @nicolas robi poniżej są dobre. Po pierwsze, wstrzyknięcie $rootScope i dołączenie tam pomocników powstrzyma cię od dodawania ich dla każdego kontrolera. Również-zgadzam się, że jeśli to co dodajesz powinno być traktowane jako kanciaste usługi lub filtry, powinny być przyjęte do kodeksu w ten sposób.

Również, od obecnej wersji 1.4.2, Angular wyświetla API" Provider", które może być wstrzykiwane do bloków konfiguracyjnych. Zobacz te zasoby, aby uzyskać więcej:

Https://docs.angularjs.org/guide/module#module-loading-dependencies

AngularJS dependency injection wartości wewnątrz modułu.config

Nie sądzę, że będę aktualizować rzeczywiste bloki kodu poniżej, ponieważ ostatnio nie używam Angular i nie chcę ryzykować nowej odpowiedzi bez poczucia, że jest ona zgodna z nowymi najlepszymi praktykami. Jeśli ktoś inny czuje się na siłach, proszę bardzo.

Edytuj 2/3/14:

Po zastanowieniu się nad tym i przeczytaniu kilku innych odpowiedzi, myślę, że wolę odmianę metody podniesionej przez @ Brent Washburne i @Amogh Talpallikar. Zwłaszcza jeśli szukasz narzędzia takie jak isNotString () lub podobne. Jedną z wyraźnych zalet jest to, że możesz ponownie użyć ich poza kodem kątowym i możesz użyć ich wewnątrz funkcji konfiguracji (której nie możesz zrobić z usługami).

Biorąc to pod uwagę, jeśli szukasz ogólnego sposobu na ponowne wykorzystanie tego, co powinno być odpowiednio usługami, stara odpowiedź, myślę, że nadal jest dobra.

To co bym teraz zrobił to:

App.js:

var MyNamespace = MyNamespace || {};

 MyNamespace.helpers = {
   isNotString: function(str) {
     return (typeof str !== "string");
   }
 };

 angular.module('app', ['app.controllers', 'app.services']).                             
   config(['$routeProvider', function($routeProvider) {
     // Routing stuff here...
   }]);

Kontroler.js:

angular.module('app.controllers', []).                                                                                                                                                                                  
  controller('firstCtrl', ['$scope', function($scope) {
    $scope.helpers = MyNamespace.helpers;
  });

Wtedy w Twoim częściowy można użyć:

<button data-ng-click="console.log(helpers.isNotString('this is a string'))">Log String Test</button>

Stara odpowiedź poniżej:

[[9]}najlepiej byłoby włączyć je jako usługę. Jeśli zamierzasz używać ich ponownie na wielu kontrolerach, w tym jako usługi, nie będziesz musiał powtarzać kodu.

Jeśli chcesz korzystać z funkcji usługi w części html, powinieneś dodać je do zakresu kontrolera:

$scope.doSomething = ServiceName.functionName;

Wtedy w części możesz użyć:

<button data-ng-click="doSomething()">Do Something</button>

Oto sposób, w jaki możesz trzymaj to wszystko zorganizowane i wolne od zbyt wielu kłopotów: {]}

Rozdziel kontroler, usługę i Kod/konfigurację routingu na trzy pliki: Kontrolery.js, usługi.js i app.js. Moduł górnej warstwy to "app", który ma aplikację.kontrolery i aplikacja.usługi jako zależności. Następnie app.kontrolery i aplikacja.usługi mogą być deklarowane jako moduły w ich własnych plikach. Ta struktura organizacyjna pochodzi właśnie z Seed :

App.js:

 angular.module('app', ['app.controllers', 'app.services']).                             
   config(['$routeProvider', function($routeProvider) {
     // Routing stuff here...
   }]);  

Usługi.js:

 /* Generic Services */                                                                                                                                                                                                    
 angular.module('app.services', [])                                                                                                                                                                        
   .factory("genericServices", function() {                                                                                                                                                   
     return {                                                                                                                                                                                                              
       doSomething: function() {   
         //Do something here
       },
       doSomethingElse: function() {
         //Do something else here
       }
    });

Kontroler.js:

angular.module('app.controllers', []).                                                                                                                                                                                  
  controller('firstCtrl', ['$scope', 'genericServices', function($scope, genericServices) {
    $scope.genericServices = genericServices;
  });

Wtedy w części możesz użyć:

<button data-ng-click="genericServices.doSomething()">Do Something</button>
<button data-ng-click="genericServices.doSomethingElse()">Do Something Else</button>

W ten sposób dodajesz tylko jeden wiersz kodu do każdego kontrolera i możesz uzyskać dostęp do dowolnej funkcji usług wszędzie tam, gdzie ten zakres jest dostępny.

 103
Author: urban_raccoons,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:54

Wchodząc na ten stary wątek chciałem podkreślić, że

1°) funkcje użytkowe mogą (powinny?) być dodawane do rootscope poprzez moduł.uciekaj. Nie ma potrzeby instancjowania określonego kontrolera poziomu głównego w tym celu.

angular.module('myApp').run(function($rootScope){
  $rootScope.isNotString = function(str) {
   return (typeof str !== "string");
  }
});

2°) jeśli uporządkujesz swój kod w osobne Moduły, powinieneś użyć angular services lub factory, a następnie wprowadzić je do funkcji przekazywanej do bloku run, w następujący sposób:

angular.module('myApp').factory('myHelperMethods', function(){
  return {
    isNotString: function(str) {
      return (typeof str !== 'string');
    }
  }
});

angular.module('myApp').run(function($rootScope, myHelperMethods){ 
  $rootScope.helpers = myHelperMethods;
});

3°) rozumiem, że w poglądach, w większości przypadków potrzebujesz tych funkcji pomocniczych, aby zastosować jakiś rodzaj formatowania do wyświetlanych ciągów. To, czego potrzebujesz w tym ostatnim przypadku, to użycie filtrów kątowych

I jeśli masz uporządkowane metody pomocnicze niskiego poziomu w usługi lub fabrykę angular, po prostu wprowadź je do konstruktora filtra:

angular.module('myApp').filter('myFilter', function(myHelperMethods){ 
  return function(aString){
    if (myHelperMethods.isNotString(aString)){
      return 
    }
    else{
      // something else 
    }
  }
);

I Twoim zdaniem:

{{ aString | myFilter }}   
 30
Author: nicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-23 21:38:04

Czy dobrze rozumiem, że po prostu chcesz zdefiniować niektóre metody użytkowe i udostępnić je w szablonach?

Nie musisz dodawać ich do każdego kontrolera. Wystarczy zdefiniować jeden kontroler dla wszystkich metod użytkowych i dołączyć go do lub

(używając dyrektywy ngController). Wszelkie inne kontrolery dołączone w dowolnym miejscu pod (czyli gdziekolwiek, kropka) lub (gdziekolwiek, ale ) odziedziczą ten $scope i będą miały dostęp do tych kontrolerów metody.
 5
Author: Willis Blackburn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-15 23:44:27

Najprostszym sposobem na dodanie funkcji użytkowych jest pozostawienie ich na poziomie globalnym:

function myUtilityFunction(x) { return "do something with "+x; }

Wtedy najprostszym sposobem dodania funkcji użytkowej (do kontrolera) jest przypisanie jej do $scope, tak:

$scope.doSomething = myUtilityFunction;

Wtedy możesz to nazwać tak:

{{ doSomething(x) }}

Lub tak:

ng-click="doSomething(x)"

EDIT:

Pierwotne pytanie brzmi, czy najlepszym sposobem na dodanie funkcji użytkowej jest usługa. Mówię NIE, jeśli funkcja jest wystarczająco prosta (jak przykład isNotString() podany przez OP).

Zaletą napisania usługi jest zastąpienie jej inną (poprzez zastrzyk) w celu przetestowania. Czy konieczne jest wprowadzenie każdej pojedynczej funkcji użytkowej do kontrolera?

Dokumentacja mówi, aby po prostu zdefiniować zachowanie w kontrolerze (jak $scope.double): http://docs.angularjs.org/guide/controller

 4
Author: Brent Washburne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-28 19:19:53

Oto prosta, zwarta i łatwa do zrozumienia metoda, której używam.
Najpierw dodaj usługę w swoim js.

app.factory('Helpers', [ function() {
      // Helper service body

        var o = {
        Helpers: []

        };

        // Dummy function with parameter being passed
        o.getFooBar = function(para) {

            var valueIneed = para + " " + "World!";

            return valueIneed;

          };

        // Other helper functions can be added here ...

        // And we return the helper object ...
        return o;

    }]);

Następnie, w kontrolerze, wstrzyknij obiekt pomocniczy i użyj dowolnej dostępnej funkcji z czymś takim jak:

app.controller('MainCtrl', [

'$scope',
'Helpers',

function($scope, Helpers){

    $scope.sayIt = Helpers.getFooBar("Hello");
    console.log($scope.sayIt);

}]);
 4
Author: Martin Brousseau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-01 02:39:39

Możesz również skorzystać z usługi stałej jako takiej. Zdefiniowanie funkcji poza wywołaniem stałym pozwala również na jej rekurencyjność.

function doSomething( a, b ) {
    return a + b;
};

angular.module('moduleName',[])
    // Define
    .constant('$doSomething', doSomething)
    // Usage
    .controller( 'SomeController', function( $doSomething ) {
        $scope.added = $doSomething( 100, 200 );
    })
;
 1
Author: b.kelley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-23 20:03:22

Dlaczego nie użyć dziedziczenia kontrolera, wszystkie metody / właściwości zdefiniowane w obszarze HeaderCtrl są dostępne w kontrolerze wewnątrz ng-view. $ scope.servHelper jest dostępny we wszystkich kontrolerach.

    angular.module('fnetApp').controller('HeaderCtrl', function ($scope, MyHelperService) {
      $scope.servHelper = MyHelperService;
    });


<div ng-controller="HeaderCtrl">
  <div ng-view=""></div>
</div>
 0
Author: Kie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-05 08:14:13