AngularJS - 使用自己的类型/提供者扩展模块

标签 angularjs angularjs-service

我想发布一个新的(对话)type到 Angular ,所以我可以像使用 module.directive 一样使用它, module.filter , module.controller注册指令、过滤器和 Controller 。

我想注册我的 dialog 实例这样输入:

module.dialog('prompt',function(dependencies){
    return {
        templateUrl:'prompt.html',
        controller:function($scope){},
        something:'value'
    }
});

我还希望能够在 Controller 中使用已注册的对话框(依赖注入(inject))
module.controller('ListCtrl',function($scope,prompt){
    $scope.deleteItem = function(item){
        prompt('Do you want to delete this item?').then(function(result){
            if(result) item.$delete();
        });
    }
});

这归结为以下问题:
  • 如何扩展 Angular 的模块以拥有 module.dialog注册我的dialog类型?
  • 如何让我的注册dialogs可注入(inject)到 controllers ETC?

  • 顺便提一句,
  • 我知道angular-uiangular-strap .
  • 我宁愿不使用 dialog作为一项服务,但作为一个单独的type (此解决方案已在 angular-ui 中实现)。
  • 最佳答案

    这是一个非常有趣的问题。我会在我的答案前加上一个意见:我认为你不应该扩展 angular.module提供dialog方法。这些方法是内置 Angular 提供程序的快捷方式,Angular 团队会不时添加一些方法。由于您无需添加 dialog 即可访问您正在寻找的功能。方法,我不会。也就是说,下面的代码确实向您展示了一个非常基本的版本是如何工作的(它不会修改 Angular 模块原型(prototype),只是模块的单个实例)。

    <div ng-app="myApp">
      <div ng-controller='MainController'>
        <div>
          <button ng-click='askName()'>Ask Name</button>
          <button ng-click='askNameAgain()'>Ask Name Again</button>
          <button ng-click='askAge()'>Ask Age</button>
          <button ng-click='askFood()'>Ask Food</button>
        </div>
        <div>{{lastResponse}}</div>
      </div>
    </div>
    

    var app = angular.module('myApp', []);
    
    // Provide some basic injectables for testing
    app.constant('nameString', 'NAME');
    app.constant('ageString', 'AGE');
    app.constant('foodString', 'FAVORITE FOOD');
    
    // Create the dialog provider
    app.provider('dialog', function($provide, $injector) {
      var dialogs = {};
    
      this.register = function(name, configFn) {
        // Create a new service
        $provide.factory(name, function($window, $q) {
          dialogs[name] = function() {
            // Get data based on DI injected version of configFn
            var data = $injector.invoke(configFn);
            // faking async here since prompt is really synchronous
            var deferred = $q.defer();
            var response = $window.prompt(data.text);
            deferred.resolve(response);
            return deferred.promise;
          };
          return dialogs[name];
        });
      };
    
      // Injecting the service itself gives you a function that
      // allows you to access a dialog by name, much like $filter
      this.$get = function() {
        return function(name) {
          return dialogs[name];
        };
      };
    });
    
    // Providing dialog injectables via app.config
    app.config(function(dialogProvider) {
      dialogProvider.register('askFood', function(foodString) {
        return { text: 'What is your ' + foodString + '?' }
      });
    });
    
    // Alternatively, shortcut to accessing the dialogProvider via app.dialog
    app.dialog = function(name, configFn) {
      app.config(function(dialogProvider) {
        dialogProvider.register(name, configFn);
      });
    };
    
    app.dialog('askName', function(nameString) {
      return { text: 'What is your ' + nameString + '?' }
    });
    
    app.dialog('askAge', function(ageString) {
      return { text: 'What is your ' + ageString + '?' }
    });
    
    app.controller('MainController', 
                   function($scope, askName, askAge, askFood, dialog) {
      var setLastResponse = function(result) {
        $scope.lastResponse = result;
      };
    
      $scope.askName = function() {
        askName().then(setLastResponse);
      };
    
      $scope.askNameAgain = function() {
        // get the dialog through the dialog service
        // much like how $filter works
        var theDialog = dialog('askName');
        theDialog().then(setLastResponse);
      };
    
      $scope.askAge = function() {
        askAge().then(setLastResponse);
      };
    
      $scope.askFood = function() {
        askFood().then(setLastResponse);
      };
    });
    

    这是一个工作示例:http://jsfiddle.net/BinaryMuse/zj4Jq/

    通过利用 $injector.invoke在你的dialogProvider.register功能,您可以提供使用像 controller 这样的键的能力在数据中你的configFn返回。由于directive已经有很多这样的工作了,您可能会从查看 the AngularJS source 中获益良多.

    关于AngularJS - 使用自己的类型/提供者扩展模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16368066/

    相关文章:

    angularjs - 如何在angular服务中使用$ on?

    javascript - 使用 Nodejs 将 MySQL 时间戳解析为 Javascript

    javascript - Angular View 中递增数字(级联 ng-repeat)

    javascript - 如何向 Angular 常量注入(inject)服务

    angularjs - $watch 在服务中?

    javascript - 为 Angular Directive(指令)提供模型名称以访问其在父级中的范围

    javascript - AngularJS:事件回调不会在谷歌地图原生 map 标记上触发

    javascript - 手动引导和覆盖配置中的 Angular 服务的问题

    angularjs - 为什么这个具有可变对象名称的 AngularJs 服务返回一个 undefined object ?

    javascript - 将服务文件中接收到的Rest数据发送到 Controller angularjs