AngularJS – extending module with own types / providers

All we need is an easy explanation of the problem, so here it is.

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:

    return {

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

    $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?


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

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

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'>
      <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>
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);
        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 + '?' }

               function($scope, askName, askAge, askFood, dialog) {
  var setLastResponse = function(result) {
    $scope.lastResponse = result;

  $scope.askName = function() {

  $scope.askNameAgain = function() {
    // get the dialog through the dialog service
    // much like how $filter works
    var theDialog = dialog('askName');

  $scope.askAge = function() {

  $scope.askFood = function() {

Here is a working example:

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.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply