AngularJS - 使用自己的类型/提供程序扩展模块 [英] AngularJS - extending module with own types / providers

查看:20
本文介绍了AngularJS - 使用自己的类型/提供程序扩展模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为 angular 添加一个新的(对话框)type,这样我就可以像使用 module.directivemodule.filter<一样使用它/code>, module.controller 用于注册指令、过滤器和控制器.

我想以这种方式注册我的 dialog 类型的实例:

module.dialog('prompt',function(dependencies){返回 {templateUrl:'prompt.html',控制器:功能($范围){},东西:'价值'}});

我也希望能够在控制器中使用注册对话框(依赖注入)

module.controller('ListCtrl',function($scope,prompt){$scope.deleteItem = function(item){prompt('你要删除这个项目吗?').then(function(result){if(result) item.$delete();});}});

这归结为以下问题:

  1. 如何扩展 angular 的模块以让 module.dialog 注册我的 dialog 类型?

  2. 如何使我注册的 dialogs 可注入到 controllers 等中?

顺便说一句,

  • 我知道 angular-uiangular-strap.
  • 我宁愿不使用 dialog 作为服务,而是作为一个单独的 type(这个解决方案已经在 angular-ui代码>).

解决方案

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

<div ng-controller='MainController'><div><button ng-click='askName()'>询问姓名</button><button ng-click='askNameAgain()'>再次询问姓名</button><button ng-click='askAge()'>询问年龄</button><button ng-click='askFood()'>询问食物</button>

<div>{{lastResponse}}</div>

var app = angular.module('myApp', []);//提供一些用于测试的基本注入app.constant('nameString', 'NAME');app.constant('ageString', 'AGE');app.constant('foodString', '最喜欢的食物');//创建对话框提供者app.provider('dialog', function($provide, $injector) {var 对话框 = {};this.register = 函数(名称,configFn){//创建一个新服务$provide.factory(name, function($window, $q) {对话框[名称] = 函数(){//根据 DI 注入的 configFn 版本获取数据var data = $injector.invoke(configFn);//这里伪造异步,因为提示是真正同步的var deferred = $q.defer();var response = $window.prompt(data.text);deferred.resolve(响应);返回 deferred.promise;};返回对话框[名称];});};//注入服务本身会给你一个函数//允许您按名称访问对话框,很像 $filterthis.$get = function() {返回函数(名称){返回对话框[名称];};};});//通过 app.config 提供对话注入app.config(function(dialogProvider) {dialogProvider.register('askFood', function(foodString) {return { text: '你的 ' + foodString + ' 是什么?}});});//或者,通过 app.dialog 访问 dialogProvider 的快捷方式app.dialog = 函数(名称,configFn){app.config(function(dialogProvider) {dialogProvider.register(name, configFn);});};app.dialog('askName', function(nameString) {return { text: '你的 ' + nameString + ' 是什么?}});app.dialog('askAge', function(ageString) {return { text: '你的 ' + ageString + ' 是什么?}});app.controller('MainController',功能($scope,askName,askAge,askFood,对话框){var setLastResponse = 函数(结果){$scope.lastResponse = 结果;};$scope.askName = function() {askName().then(setLastResponse);};$scope.askNameAgain = function() {//通过对话服务获取对话//很像 $filter 的工作方式var theDialog = dialog('askName');theDialog().then(setLastResponse);};$scope.askAge = function() {askAge().then(setLastResponse);};$scope.askFood = function() {askFood().then(setLastResponse);};});

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

通过利用 dialogProvider.register 函数内部的 $injector.invoke,您可以提供在configFn 返回的数据.由于 directive 已经很像这样,您可能会从 AngularJS 源代码.

I want to ad a new (dialog) type to angular, so I could use it just like I use module.directive, module.filter, module.controller to register directives, filters and controllers.

I want to register my instances of dialog type this way:

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

I also want to be able to use registered dialogs in controllers (dependency injection)

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

This boils down to the following questions:

  1. How do I extend angular's module to have module.dialog register my dialog types ?

  2. How do I make my registered dialogs injectable in to controllers etc?

Btw,

  • I know about angular-ui and angular-strap.
  • I would rather not use dialog as a service, but as a separate type (this solution is already implemented in angular-ui).

解决方案

This is a pretty interesting question. I'll prefix my answer with an opinion: I don't think you should extend angular.module to provide a dialog method. Those methods are shortcuts into built-in Angular providers, and the Angular team adds some from time to time. Since you can get access to the functionality you're looking for without adding the dialog method, I wouldn't. That said, the code below does show you how a very basic version of this might work (it doesn't modify the Angular module prototype, just the single instance of the module).

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

Here is a working example: http://jsfiddle.net/BinaryMuse/zj4Jq/

By leveraging $injector.invoke inside of your dialogProvider.register function, you can provide the ability to use a key like controller in the data your configFn returns. Since directive works a lot like this already, you may gain a lot from checking out the AngularJS source.

这篇关于AngularJS - 使用自己的类型/提供程序扩展模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆