How do I add a reusable modal dialog in Angular?
Asked Answered
A

3

6

I'm new to Angular and attempting to implement this solution into my project.

It looks painfully easy, however, I'm trying to make this into a re-usable element so that I can call it from anywhere and just pass in the content to be shown (otherwise, what's the point?).

So, my specific question is: assuming I already have a controller that's bound to some DOM element and it has a feature that goes and fetches some factory driven $http call and upon the response I wish to notify the user via this dialog of something, how do I combine *this directive and *this controller with my existing one and how do I do it in a way that allows me to then use it again from a totally different controller?

Or is this perhaps a bad example for this use and should I be looking at a different one?

Audrey answered 16/8, 2014 at 16:34 Comment(0)
P
8

Compared to other options, below given the minimalist approach, using angular factory. See a sample snippet below.

Note: using Angular JS with UI Bootstrap - AngularUI.

  1. Reusable modal view - ConfirmationBox.html

<div class="modal-header">
  <h3 class="modal-title">{{title}}</h3>
</div>
<div class="modal-body">
  {{message}}
</div>
<div class="modal-footer">
  <button type="button" class="btn btn-primary btn-warn" data-ng-click="ok(); $event.stopPropagation()">OK</button>

  <button type="button" class="btn btn-default" data-ng-click="cancel(); $event.stopPropagation()">Cancel</button>
</div>
  1. Reusable module and shared factory, for handling the reusable modal dialog

angular.module('sharedmodule',['ui.bootstrap', 'ui.bootstrap.tpls'])
.factory("sharedService",["$q", "$modal", function ($q, $modal)
{
    var _showConfirmDialog = function (title, message)
    {
        var defer = $q.defer();

        var modalInstance = $modal.open({
            animation: true,
            size: "sm",
            templateUrl: 'ConfirmationBox.html',
            controller: function ($scope, $modalInstance)
            {
                $scope.title = title;
                $scope.message = message;

                $scope.ok = function ()
                {
                    modalInstance.close();
                    defer.resolve();
                };

                $scope.cancel = function ()
                {
                    $modalInstance.dismiss();
                    defer.reject();
                };
            }
        });

        return defer.promise;
    }

    return {

        showConfirmDialog: _showConfirmDialog
    };

}]);
  1. Portion of your View, using the shared modal dialog

<a data-ng-click="showConfirm()">Go Back to previous page</a>
  1. Controller of your view, opening your shared reusable modal dialog and handling notifications (Ok and Cancel)

var myModule = angular.module("mymodule", ['sharedmodule', 'ui.bootstrap', 'ui.bootstrap.tpls']);

myModule.controller('myController', ["$scope", "sharedService", "$window",
function ($scope, sharedService, $window)
{
    $scope.showConfirm = function ()
    {
        sharedService.showConfirmDialog(
            'Confirm!',
            'Any unsaved edit will be discarded. Are you sure to navigate back?')
            .then(function ()
            {
                $window.location = '#/';
            },
            function ()
            {
            });
    };
}]);
Preternatural answered 1/7, 2015 at 17:35 Comment(0)
O
2

Trying using 'ngDialog' library for popup and modal. Very good library. Later you can create a service which internally calls ngDialog functions. Later this service can be injected in your controllers for use. I have implemented this in one project.

The function in services can accept parameters for initialising the ngDialog modal.

Hope it helps :)

Obrian answered 16/8, 2014 at 18:4 Comment(2)
wow... that is absolutely the way to go! :-) No idea what the limitations are, and ultimately I'd like to get the answer to this question specifically (about creating universally accessible elements) but thanks very much for that tip, very useful library.Audrey
I wouldn't use 'ngDialog' library for complex windows. It doesn't allow dragging and resizing. In my project it broke animation. Sometimes it stops responds any clicks on buttons till browser page reloads.Conclude
R
1

for making it better I would suggest you to modify the code to look something as below

Template:

<div class='ng-modal' ng-show='modalContent != null && modalContent != ""'>
  <div class='ng-modal-overlay' ng-click='hideModal()'></div>
  <div class='ng-modal-dialog' ng-style='dialogStyle'>
    <div class='ng-modal-close' ng-click='hideModal()'>X</div>
    <div class='ng-modal-dialog-content' ng-transclude></div>
    <p>{{ modalContent }}</p>
  </div>
</div>

Directive:

app.directive('modalDialog', function() {
  return {
    restrict: 'E',
    scope: {
      modalContent: '='
    },
    replace: true, // Replace with the template below
    transclude: true, // we want to insert custom content inside the directive
    link: function(scope, element, attrs) {
      scope.dialogStyle = {};
      if (attrs.width)
        scope.dialogStyle.width = attrs.width;
      if (attrs.height)
        scope.dialogStyle.height = attrs.height;
      scope.hideModal = function() {
        scope.modalContent= null;
      };
    },
    template: '...' // See below
  };
});

and then use the code as below in template

<modal-dialog modal-content='modalMsg' width='750px' height='90%'></modal-dialog>

Once these changes are done you can write a function to set message in variable "modalMsg" and angular will take care of rest

Note: Code is pretty much the same as in the link, the only thing I have changed is the check to display the modal box

Riva answered 16/8, 2014 at 18:20 Comment(3)
thanks. My confusion revolves around how to make this code universally accessible to any controller. How do I bind this directive to 'someArbitraryController' and where in the DOM do I put the <modal-dialog> and associated <div>s? I have my controller templates as separate HTML files that are being routed to. My desire is to be able to call this directive from anywhere... does that make sense?Audrey
<modal-dialog> needs to be part of each and every template that requires a modal window and then you can set the text (in the variable used for modalContent) from its controller. you don't need to bind any additional controller with this. I am not 100% sure but I guess you are looking for something like ng-dialog as in comments by Max. If thats what you require than you may want to create your own provider docs.angularjs.org/guide/providers (using your link as reference). Same is done for ng-dialogRiva
yes, I believe my own provider is the only way to make it universal. I'm starting to wrap my head around this now... (slowly)Audrey

© 2022 - 2024 — McMap. All rights reserved.