Как добавить некоторые небольшие служебные функции в приложение AngularJS?

Я хотел бы добавить некоторые утилиты в мое приложение AngularJS. Например:

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

Это лучший способ сделать это, чтобы добавить их в качестве службы? Из того, что я прочитал, я могу сделать это, но тогда я хотел бы использовать их на своих HTML-страницах, так что все еще возможно, если они на службе? Например, могу ли я использовать следующее:

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

Может кто-нибудь дать мне пример того, как я мог бы добавить их. Создать сервис или есть другой способ сделать это. Самое главное, я бы хотел, чтобы эти утилиты функции в файле и не объединены с другой частью основной настройки.

Я понимаю, что есть несколько решений, но ни один из них не настолько ясен.

Решение 1 - Предлагается Urban

$scope.doSomething = ServiceName.functionName;

Проблема здесь в том, что у меня есть 20 функций и десять контроллеров. Если бы я это сделал, это означало бы добавление большого количества кода в каждый контроллер.

Решение 2 - Предлагаемый мной

    var factory = {

        Setup: function ($scope) {

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

Недостаток этого заключается в том, что в начале каждого контроллера у меня будет один или несколько из этих вызовов установки для каждой службы, которая передала $scope.

Решение 3 - Предлагается Urban

Решение, предлагаемое городскими службами создания общего сервиса, выглядит неплохо. Здесь моя основная настройка:

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

Должен ли я добавить общий сервис к этому и как я могу это сделать?

Ответ 1

EDIT 7/1/15:

Я написал этот ответ довольно давно и не слишком много поддерживал с angular, но кажется, что этот ответ по-прежнему относительно популярен, поэтому я хотел указать, что пара из пункта @nicolas делает ниже, хороши. Например, при вводе $rootScope и прикреплении помощников вам не придется добавлять их для каждого контроллера. Кроме того, я согласен, что если то, что вы добавляете, следует рассматривать как angular services OR filters, они должны быть приняты в код таким образом.

Кроме того, начиная с текущей версии 1.4.2, angular предоставляет API-интерфейс "Provider", который разрешается вводить в блоки конфигурации. Подробнее см. В этих ресурсах:

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

Угловая зависимость значения внутри модуля module.config

Я не думаю, что я собираюсь обновить фактические блоки кода ниже, потому что я не очень активно использую angular в эти дни, и я действительно не хочу подвергать опасности новый ответ, не чувствуя себя комфортно, фактически соответствуя новым передовым методам. Если кто-то чувствует это, непременно пойдет на это.

РЕДАКТИРОВАТЬ 2/3/14:

Подумав об этом и прочитав некоторые другие ответы, я действительно думаю, что предпочитаю вариацию метода, поднятого @Brent Washburne и @Amogh Talpallikar. Особенно, если вы ищете утилиты, такие как isNotString() или аналогичные. Одно из очевидных преимуществ здесь заключается в том, что вы можете повторно использовать их вне своего кода angular, и вы можете использовать их внутри своей конфигурации (что вы не можете делать с сервисами).

Если говорить о том, что вы ищете общий способ повторного использования того, что должно быть надлежащим образом, то старый ответ, который, как мне кажется, по-прежнему остается хорошим.

Теперь я бы сделал следующее:

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

controller.js:

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

Затем в частичном вы можете использовать:

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

Старый ответ ниже:

Лучше всего включить их в качестве службы. Если вы собираетесь повторно использовать их через несколько контроллеров, включая их как службу, вам не придется повторять код.

Если вы хотите использовать служебные функции в части вашего html, то вы должны добавить их в область этого контроллера:

$scope.doSomething = ServiceName.functionName;

Затем в частичном вы можете использовать:

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

Здесь вы можете сохранить все это организованным и свободным от слишком много хлопот:

Разделите свой контроллер, службу и код маршрутизации/конфигурации на три файла: controllers.js, services.js и app.js. Модуль верхнего уровня - это "приложение", в котором есть приложения и приложения. В качестве зависимостей. Затем app.controllers и app.services могут быть объявлены как модули в своих файлах. Эта организационная структура просто взята из Angular Seed:

app.js:

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

services.js:

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

controller.js:

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

Затем в частичном вы можете использовать:

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

Таким образом, вы добавляете только одну строку кода для каждого контроллера и можете обращаться к любой из функций служб, где доступна эта область.

Ответ 2

Находясь в этом старом потоке, я хотел подчеркнуть, что

1 °) функции полезности могут (должны?) быть добавлены в корневой модуль через module.run. Для этой цели нет необходимости устанавливать конкретный контроллер уровня корня.

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

2 °). Если вы упорядочиваете свой код на отдельные модули, вы должны использовать angular services или factory, а затем введите их в функцию, переданную в блок выполнения, как показано ниже:

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 °) Я понимаю, что в представлениях для большинства случаев вам нужны эти вспомогательные функции, чтобы применить какое-то форматирование к отображаемым строкам. В этом последнем случае вам понадобится использовать angular фильтры

И если вы структурировали некоторые вспомогательные методы низкого уровня в сервисах angular или factory, просто введите их в свой конструктор фильтра:

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

И на ваш взгляд:

{{ aString | myFilter }}   

Ответ 3

Правильно ли я понимаю, что вы просто хотите определить некоторые методы утилиты и сделать их доступными в шаблонах?

Вам не нужно добавлять их к каждому контроллеру. Просто определите один контроллер для всех методов утилиты и присоедините этот контроллер к <html> или <body> (используя директиву ngController). Любые другие контроллеры, которые вы прикрепляете где-нибудь под <html> (что означает где угодно, период) или <body> (где угодно, но <head> ), наследуют эту область $scope и будут иметь доступ к этим методам.

Ответ 4

Самый простой способ добавить служебные функции - оставить их на глобальном уровне:

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

Тогда самый простой способ добавить функцию утилиты (к контроллеру) - назначить ее $scope, например:

$scope.doSomething = myUtilityFunction;

Затем вы можете вызвать его так:

{{ doSomething(x) }}

или вот так:

ng-click="doSomething(x)"

EDIT:

Исходный вопрос заключается в том, что лучший способ добавить функцию утилиты - через сервис. Я говорю "нет", если функция достаточно проста (например, пример isNotString(), предоставленный OP).

Преимущество написания услуги заключается в замене ее другим (посредством инъекции) для целей тестирования. В крайнем случае, нужно ли вводить каждую функцию утилиты в контроллер?

В документации говорится просто определить поведение в контроллере (например, $scope.double): http://docs.angularjs.org/guide/controller

Ответ 5

Вот простой, компактный и понятный метод, который я использую. Сначала добавьте службу в 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;

    }]);

Затем в контроллере введите свой вспомогательный объект и используйте любую доступную функцию с помощью следующего:

app.controller('MainCtrl', [

'$scope',
'Helpers',

function($scope, Helpers){

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

}]);

Ответ 6

Почему бы не использовать наследование контроллера, все методы/свойства, определенные в области HeaderCtrl, доступны в контроллере внутри ng-view. $scope.servHelper доступен во всех ваших контроллерах.

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


<div ng-controller="HeaderCtrl">
  <div ng-view=""></div>
</div>

Ответ 7

Вы также можете использовать постоянную службу как таковую. Определение функции вне постоянного вызова позволяет также быть рекурсивным.

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

angular.module('moduleName',[])
    // Define
    .constant('$doSomething', doSomething)
    // Usage
    .controller( 'SomeController', function( $doSomething ) {
        $scope.added = $doSomething( 100, 200 );
    })
;