Angular Modal dialogs

We like the ngDialog plugin, which makes nice-looking dialogs, and they're quite easy to do. We have included styling for it in the uicommons module under the default theme (ngdialog-theme-default).

Usage example, for a Confirm dialog:

GSP view using a dialog
<%
    ui.includeJavascript("uicommons", "angular.js")
    ui.includeJavascript("uicommons", "ngDialog/ngDialog.js")
    ui.includeCss("uicommons", "ngDialog/ngDialog.min.css")
    // you also need to have included referenceapplication.css or similar, which usually happens globally through the distribution
 
    // also include your page's js
%>
 
<div id="your-page-app" ng-controller="YourPageCtrl">
    <script type="text/ng-template" id="dialogTemplate">
        <div class="dialog-header">
            <h3>Doing something</h3>
        </div>
        <div class="dialog-content">
            <div>
                Why? <input type="text" ng-model="reason"/>
                {{ ngDialogData.helperData }}
            </div>
            <div>
                <button class="confirm right" ng-click="confirm(reason)">${ ui.message("uicommons.save") }</button>
                <button class="cancel" ng-click="closeThisDialog()">${ ui.message("uicommons.cancel") }</button>
            </div>
        </div>
    </script>
 
    <a ng-click="showDialog()">
        <i class="icon-plus-sign"></i>
        Show dialog
    </a>
</div>
 
<script type="text/javascript">
    // manually bootstrap angular app, in case there are multiple angular apps on a page
    angular.bootstrap('#your-page-app', ['yourpageapp']);
</script>

 

The JavaScript backing this is:

angular.module('yourpageapp', ['ngDialog']). // make sure to declare a dependency on ngDialog in your app
 
controller('YourPageCtrl', ['$scope', 'ngDialog',
function($scope, ngDialog) {
    $scope.showDialog = function() {
        ngDialog.openConfirm({
            showClose: false,
            closeByEscape: true,
            closeByDocument: true,
            data: angular.toJson({
                helperData: "One way to push data into the dialog"
            }),
            template: 'dialogTemplate' // in this example we defined this inline with <script type="ng-template"> but you can also give a url
        }).then(function(reason) {
            console.log("They chose reason: " + reason);
        }, function() {
            console.log("They clicked cancel");
        });
    };
}]);

 

Advanced

There are a several different ways to pass data into the dialog from the enclosing controller, each of which you might use at different times:

Using "data"

Pro: Cleaner JavaScript code.

Con: Annoying need to refer to "ngDialogData" in the view. Could be expensive for a huge data model.

Pushing data into the dialog with 'data'
confirmDeleteRelationship = function(rel) {
    ngDialog.openConfirm({
        data: angular.toJson({
            relationship: rel
        })
        template: "..."
    });
}
 
// in the view you can do something like this:
//   {{ ngDialogData.relationship.personA }} is related
//   via {{ ngDialogData.relationship.relationshipType.display }}
//   to {{ ngDialogData.relationship.personB }}

 

Using "scope"

Pro: Cleaner view code. More control and power.

Con: Non-obvious boilerplate JavaScript

Pushing data into the dialog with a custom scope
$scope.helperFunction = function(x) { return "something" };
 
confirmDeleteRelationship = function(rel) {
    var dialogScope = $scope.$new();  // Doing $scope.$new(true) instead gives an isolated scope (with no access to helperFunction)
    angular.extend(dialogScope, {
        relationship: rel
    });
    ngDialog({
        scope: dialogScope,
        template: "..."
    })
    .finally(function() {
        dialogScope.$destroy(); // I assume you need to do this to avoid leaking resources
    });
}

// in the view you can do something like this:
//   {{ relationship.personA }} is related
//   via {{ relationship.relationshipType.display }}
//   to {{ relationship.personB }}
//
// and you can also access
//   {{ helperFunction(relationship) }}

 

Using a controller

Pro: this is the best (I hadn't tried it yet when I wrote all the above)

It works something like this (I haven't actually tested this code)

confirmDeleteRelationship = function(rel) {
    ngDialog({
        controller: ["$scope", function($scope) { // you can also inject a service with helper functions
			$scope.relationship = rel;
		}],
        template: "..."
    });
}
 
// in the view you can do something like this:
//   {{ relationship.personA }} is related
//   via {{ relationship.relationshipType.display }}
//   to {{ relationship.personB }}