如何在AngularJS应用程序中添加一些小实用程序功能?

时间:2013-10-27 04:11:38

标签: 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个功能和10个控制器。如果我这样做,则意味着向每个控制器添加大量代码。

解决方案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);

我应该将通用服务添加到此,我该怎么做?

7 个答案:

答案 0 :(得分:105)

编辑7/1/15:

我很久以前写过这个答案,并且在一段时间内没有用角度保持很多,但似乎这个答案仍然比较受欢迎,所以我想指出一些点@nicolas以下是好的。首先,注入$ rootScope并在其中附加帮助程序将使您不必为每个控制器添加它们。另外 - 我同意如果您要添加的内容应该被视为Angular服务或过滤器,那么它们应该以这种方式被采用到代码中。

此外,从当前版本1.4.2开始,Angular公开了一个“Provider”API,允许将其注入配置块。有关更多信息,请参阅以下资源:

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

AngularJS dependency injection of value inside of module.config

我认为我不会更新下面的实际代码块,因为这些天我并没有真正积极地使用Angular而且我真的不想冒新的答案而不觉得它确实符合新的最佳实践。如果其他人感觉到这一点,那么一定要去做吧。

编辑2/3/14:

在考虑了这个问题并阅读了其他一些答案后,我实际上认为我更喜欢@Brent Washburne和@Amogh Talpallikar提出的方法的变体。特别是如果你正在寻找像isNotString()或类似的实用程序。这里一个明显的优点是你可以在角度代码之外重复使用它们,你可以在你的配置功能中使用它们(你不能用服务做)。

话虽如此,如果你正在寻找一种通用的方法来重新使用正确的服务,我认为旧的答案仍然很好。

我现在要做的是:

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 partial中使用服务功能,那么您应该将它们添加到该控制器的范围:

$scope.doSomething = ServiceName.functionName;

然后在你的部分你可以使用:

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

这是一种你可以保持这种有条理并且没有太多麻烦的方式:

将控制器,服务和路由代码/配置分成三个文件:controllers.js,services.js和app.js.顶层模块是“app”,它有app.controllers和app.services作为依赖项。然后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>

这样,您只需向每个控制器添加一行代码,并且只要访问该范围,就可以访问任何服务函数。

答案 1 :(得分:30)

来到这个旧线程我想强调

1°)实用程序函数可以(应该?)通过module.run添加到rootscope。没有必要为此目的实例化特定的根级控制器。

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

2°)如果将代码组织到单独的模块中,则应使用角度servicesfactory,然后将它们注入传递给运行块的函数中,如下所示:

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°)我的理解是,在视图中,对于大多数情况,您需要这些辅助函数将某种格式应用于您显示的字符串。在最后一种情况下,您需要使用有角度的filters

如果你已经将一些低级辅助方法构建到角度服务或工厂中,只需将它们注入到过滤器构造函数中:

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

在你看来:

{{ aString | myFilter }}   

答案 2 :(得分:6)

我是否理解您只想定义一些实用工具方法并在模板中使用它们?

您不必将它们添加到每个控制器。只需为所有实用程序方法定义一个控制器,并将该控制器附加到&lt; html&gt;或者&lt; body&gt; (使用ngController指令)。您在&lt; html&gt;下的任何地方附加的任何其他控制器(意思是任何地方,期间)或&lt; body&gt; (除了&lt; head&gt;之外的任何地方)将继承该范围,并且可以访问这些方法。

答案 3 :(得分:4)

添加实用程序功能的最简单方法是将它们保留在全局级别:

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

然后,添加实用程序功能(到控制器)的最简单方法是将其分配给$scope,如下所示:

$scope.doSomething = myUtilityFunction;

然后你可以这样称呼它:

{{ doSomething(x) }}

或者像这样:

ng-click="doSomething(x)"

编辑:

最初的问题是,添加效用函数的最佳方法是通过服务。我说不,如果函数足够简单(比如OP提供的isNotString()示例)。

编写服务的好处是将其替换为另一个(通过注入)以进行测试。极端情况下,您是否需要将每个实用功能注入控制器?

文档说只是在控制器中定义行为(如$scope.double):http://docs.angularjs.org/guide/controller

答案 4 :(得分:4)

这是一个简单,紧凑且易于理解的方法 首先,在你的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);

}]);

答案 5 :(得分:1)

您也可以使用常量服务。在常量调用之外定义函数也允许它是递归的。

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

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

答案 6 :(得分:0)

为什么不使用控制器继承,可以在ng-view内的控制器中访问HeaderCtrl范围内定义的所有方法/属性。 $ scope.servHelper可在所有控制器中访问。

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


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