<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js@*" data-semver="1.2.0-rc3-nonmin" src="http://code.angularjs.org/1.2.0-rc.3/angular.js"></script>
<script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<link data-require="jqueryui@*" data-semver="1.10.0" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/css/smoothness/jquery-ui-1.10.0.custom.min.css" />
<script data-require="jqueryui@*" data-semver="1.10.0" src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.10.0/jquery-ui.js"></script>
<script src="dialog-service.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="dialogApp">
<!--
The button that displays the dialog when pressed
-->
<div ng-controller="buttonCtrl">
<button ng-click="openClick()">Test</button>
</div>
<!--
This is the template for the main dialog that is displayed. It uses the
dialogCtrl controller in app.js.
-->
<script type="text/ng-template" id="dialogTemplate.html">
<div ng-controller="dialogCtrl">
First Name<br>
<input type="text" ng-model="model.firstName" /><br>
Last Name<br>
<input type="text" ng-model="model.lastName" /><br>
<button ng-click="cancelClick()">Cancel</button>
<button ng-click="saveClick()">Save</button>
<button ng-click="confirmClick()">Confirm</button>
</div>
</script>
<!--
This is the template for the confirmation popup. It uses the confirmCtrl
controller in app.js.
-->
<script type="text/ng-template" id="confirmTemplate.html">
<div ng-controller="confirmCtrl">
Are you sure?
<button ng-click="confirmClick()">Yes</button>
<button ng-click="cancelClick()">No</button>
</div>
</script>
</body>
</html>
angular-jquery-dialog-service
=============================
# Overview
This service allows you to easily work with jQuery UI dialogs from Angular.js. A working sample can be viewed on [Plunker][2].
# Methods
The service exposes three methods for controlling the dialogs. These methods are `open()`, `close()`, and `cancel()`.
## open(id, template, model, options)
The open method displays a dialog. The `id` argument is a unique name to identify this dialog when calling other methods on the service such as close and cancel.
The `template` argument specifies the id of the script block that contains the template to use for the dialog. Here is an example template:
```
<script type="text/ng-template" id="dialogTemplate.html">
<!-- Controller for Dialog -->
<div ng-controller="dialogCtrl">
<!-- The form -->
First Name<br>
<input type="text" ng-model="model.firstName" /><br>
Last Name<br>
<input type="text" ng-model="model.lastName" /><br>
<!-- The buttons -->
<button ng-click="cancelClick()">Cancel</button>
<button ng-click="saveClick()">Save</button>
<button ng-click="confirmClick()">Confirm</button>
</div>
</script>
```
In the case above, `template` would be set to "dialogTemplate.html".
The `model` argument contains the data that should be passed to the dialog controller's scope. It is actually injected into the dialog controller's parent scope, but it is available as `$scope.model` within the dialog.
Finally, the `options` argument contains all of the [jQuery UI dialog options][1] that you would normally pass in the call to `dialog(options)`.
The open method returns a promise that is resolved when the user closes the dialog. If the dialog controller calls dialogService.close(model), the resolve function will be called. If `cancel()` is called or the user closed the dialog using the X or ESC, the reject function will be called.
Here is an example of an open call that opens a dialog whose template is in a script block assigned an id of "dialogTemplate.html":
```javascript
dialogService.open("myDialog","dialogTemplate.html",
model: {
firstName: "Jason",
lastName: "Stadler",
update: false
},
options: {
autoOpen: false,
modal: true
}
}).then(
function(result) {
console.log("Closed");
console.log(result);
},
function(error) {
console.log("Cancelled");
}
);
```
## close(id, model)
This method is typically called by the dialog controller to close the dialog. The `id` argument is the same string passed to the open method. The `model` is the data the dialog should pass back in the promise to the caller.
## cancel(id)
This method is typically called by the dialog controller to cancel the dialog. The `id` argument is the same string passed to the open method.
[1]: http://api.jquery.ui/dialog "JQuery UI Dialog Documentation"
[2]: http://plnkr.co/edit/ADYEsplnYr8NHqASCDgS "Plunker sample"
var app = angular.module('dialogApp', ['dialogService']);
app.controller('buttonCtrl', ['$scope', 'dialogService',
function($scope, dialogService) {
$scope.openClick = function() {
// The data for the dialog
var model = {
firstName: "Jason",
lastName: "Stadler"
};
// jQuery UI dialog options
var options = {
autoOpen: false,
modal: true,
close: function(event, ui) {
console.log("Predefined close");
}
};
// Open the dialog
dialogService.open("myDialog","dialogTemplate.html", model, options)
.then(
function(result) {
console.log("Close");
console.log(result);
},
function(error) {
console.log("Cancelled");
}
);
};
}
]);
app.controller('dialogCtrl', ['$scope', 'dialogService',
function($scope, dialogService) {
// $scope.model contains the object passed to open in config.model
$scope.saveClick = function() {
dialogService.close("myDialog", $scope.model);
};
$scope.cancelClick = function() {
dialogService.cancel("myDialog");
};
$scope.confirmClick = function() {
// Open another dialog here
dialogService.open("myConfirm", "confirmTemplate.html")
.then(
function(result) {
console.log("Confirm");
},
function(error) {
console.log("Cancel");
}
);
};
}
]);
app.controller('confirmCtrl', ['$scope', 'dialogService',
function($scope, dialogService) {
$scope.confirmClick = function() {
dialogService.close("myConfirm");
};
$scope.cancelClick = function() {
dialogService.cancel("myConfirm");
};
}
]);
angular.module('dialogService', []).service('dialogService',
['$rootScope', '$q', '$compile', '$templateCache',
function($rootScope, $q, $compile, $templateCache) {
_this = this;
this.dialogs = {};
this.open = function(id, template, model, options) {
// Check our required arguments
if (!angular.isDefined(id)) {
throw "dialogService requires id in call to open";
}
if (!angular.isDefined(template)) {
throw "dialogService requires template in call to open";
}
// Set the defaults for model
if (!angular.isDefined(model)) {
model = null;
}
// Copy options so the change ot close isn't propogated back.
// Extend is used instead of copy because window references are
// often used in the options for positioning and they can't be deep
// copied.
var dialogOptions = {};
if (angular.isDefined(options)) {
angular.extend(dialogOptions, options);
}
// Initialize our dialog structure
var dialog = { scope: null, ref: null, deferred: null };
// Get the template and trim to make it valid
var dialogTemplate = $templateCache.get(template);
if (!angular.isDefined(dialogTemplate)) {
throw "dialogService could not find template " + template;
}
dialogTemplate = dialogTemplate.trim();
// Create a new scope, inherited from the parent.
dialog.scope = $rootScope.$new();
dialog.scope.model = model;
var dialogLinker = $compile(dialogTemplate);
dialog.ref = $(dialogLinker(dialog.scope));
// Hande the case where the user provides a custom close and also
// the case where the user clicks the X or ESC and doesn't call
// close or cancel.
var customCloseFn = dialogOptions.close;
var cleanupFn = this.cleanup;
dialogOptions.close = function(event, ui) {
if (customCloseFn) {
customCloseFn(event, ui);
}
cleanupFn(id);
};
// Initialize the dialog and open it
dialog.ref.dialog(dialogOptions);
dialog.ref.dialog("open");
// Cache the dialog
_this.dialogs[id] = dialog;
// Create our promise, cache it to complete later, and return it
dialog.deferred = $q.defer();
return dialog.deferred.promise;
};
this.close = function(id, result) {
// Get the dialog and throw exception if not found
var dialog = _this.getExistingDialog(id);
// Notify those waiting for the result
// This occurs first because the close calls the close handler on the
// dialog whose default action is to cancel.
dialog.deferred.resolve(result);
// Close the dialog (must be last)
dialog.ref.dialog("close");
};
this.cancel = function(id) {
// Get the dialog and throw exception if not found
var dialog = _this.getExistingDialog(id);
// Notify those waiting for the result
// This occurs first because the cancel calls the close handler on the
// dialog whose default action is to cancel.
dialog.deferred.reject();
// Cancel and close the dialog (must be last)
dialog.ref.dialog("close");
};
/* private */
this.cleanup = function(id) {
// Get the dialog and throw exception if not found
var dialog = _this.getExistingDialog(id);
// This is only called from the close handler of the dialog
// in case the x or escape are used to cancel the dialog. Don't
// call this from close, cancel, or externally.
dialog.deferred.reject();
dialog.scope.$destroy();
// Remove the object from the DOM
dialog.ref.remove();
// Delete the dialog from the cache
delete _this.dialogs[id];
};
/* private */
this.getExistingDialog = function(id) {
// Get the dialog from the cache
var dialog = _this.dialogs[id];
// Throw an exception if the dialog is not found
if (!angular.isDefined(dialog)) {
throw "DialogService does not have a reference to dialog id " + id;
}
return dialog;
};
}
]);