AngularJS - extending module with own types / providers

后端 未结 1 843
逝去的感伤
逝去的感伤 2021-02-04 15:34

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

1条回答
  •  再見小時候
    2021-02-04 16:32

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

    {{lastResponse}}
    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.

    0 讨论(0)
提交回复
热议问题