Bootstrap Dialog

by zdam

HTML

<!doctype html>
<html ng-app="dialog">
  <head>
    <title>Bootstrap Test</title>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css">
    <script src="http://code.jquery.com/jquery-1.7.1.js"></script>
    <script src="http://twitter.github.com/bootstrap/1.4.0/bootstrap-modal.js"></script>
    <script src="http://ci.angularjs.org/job/angular.js-angular-master/201/artifact/build/pkg/0.10.7-8b32900d/angular-0.10.7-8b32900d.js"></script>
  </head>
  <body>
    <div ng-controller="MainCtrl">
        <h2>Hello {{username}}!</h2>
        ng+bootstrap: <a class="btn" ng-click="changeUserNameDialog = true">change username</a>

        <bs-dialog when="changeUserNameDialog"
                   title="Change your username"
                   primary-label="Change"
                   primary-action="changeName(username)">
          <p>You can change your username to anything you want.</p>
          <label for="username">new username:</label><input name="username" ng-model="username">
        </bs-dialog>
    </div>

    <!-- angular dialog template -->
    <script type="text/ng-template" id="dialog-template">
      <div id="my-modal" class="modal hide fade">
        <div class="modal-header">
          <a class="close">&times;</a>
          <h3>{{title}}</h3>
        </div>
        <div class="modal-body">
        </div>
        <div class="modal-footer">
          <a class="btn primary" ng-click="primaryAction()">{{primaryLabel}}</a>
          <a class="btn secondary" ng-click="secondaryAction()">{{secondaryLabel}}</a>
        </div>
      </div>
    </script>
  </body>
</html>

JavaScript

function MainCtrl($scope) {
  $scope.username = 'Adam Webber';
  $scope.changeName = function(name) {
    $scope.username = name;
  }
}

dialogApp = angular.module('dialog', []);

dialogApp.directive('bsDialog', function($templateCache, $document, $compile) {
  return {
    terminal: true,
    link: function(scope, element, attrs) {
      var dialogElement,
          dialogBodyElement,
          dialogScope,
          dialogBodyScope,
          dialogBodyTemplate = element.contents();

      element.remove();

      scope.$watch(attrs.when, function(show) {
        if (show) {
          dialogScope = scope.$new(); // maybe even use $rootScope instead
          dialogBodyScope = scope.$new(); // must be child of scope => no need to export model

          angular.extend(dialogScope, {
            title: attrs.title,
            primaryLabel: attrs.primaryLabel || 'OK',
            secondaryLabel: attrs.secondaryLabel || 'Cancel',
            closeDialog: function() {
              dialogElement.modal('hide');
            },
            primaryAction: function() {
              this.closeDialog();
              dialogBodyScope.$eval(attrs.primaryAction);
            },
            secondaryAction: function() {
              this.closeDialog();
              dialogBodyScope.$eval(attrs.secondaryAction);
            }
          });

          dialogElement = $($templateCache.get('dialog-template'));
          $document.append(dialogElement);
          $compile(dialogElement)(dialogScope);
          dialogBodyElement = dialogElement.find('.modal-body');
          dialogBodyElement.append(dialogBodyTemplate);
          $compile(dialogBodyElement)(dialogBodyScope);

          dialogElement.modal('show');
          dialogElement.bind('hidden', function() {
            scope.$apply(function() {
              dialogScope.$destroy();
              dialogBodyScope.$destroy();
              dialogElement.remove();
              dialogElement = null;
             ...