<!DOCTYPE html>
<html ng-app="myApp">
  <head lang="en">
    <meta charset="utf-8">
    <title>Bootstrap-AngularJS Modal - Directive</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
    <script src="controller.js"></script>
    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap-combined.min.css"
    rel="stylesheet">
    <style>
      .modal-large {
        width: 590px;
      	height: 650px;	
      	left: 35%;
      	margin: -400px 0 0 -150px;
      	top: 50%;
      } 
    </style>
  </head>  
  <body ng-controller="Controller">
    <div class="span12">
      <h1>Bootstrap Modal</h1>
      <p>The bootstrap modal directive allows you to open three different
        types of modal windows:
      </p>
      <p>
        <ul>
          <li><b>Confirm</b></li>
          <li><b>Alert</b></li>
          <li><b>Dialog</b></li>
        </ul>
      </p>
      <p>Confirm and alert get their content from referenced <b>div</b>
        elements. These elements should contain the basic structure of a 
        typical modal window, analogous to the specs, which can be found in 
        Twitter Bootstrap. All tags are referenced via <b>modal="reference"</b>
        and catching the <b>id</b> of the target element.
        <br/>
        The dialog modal is able to reference an URI to a view, which will be
        loaded into the modal window. All <b>ng-click</b> events are mapped
        through the directive and catchable in the parent controller. A modal
        can be close by setting <b>$scope.closeModal</b>
      </p>
      <p>The properties to configure the modal are as follows:</p>
      <p>
        <ul>
          <li><b>modal</b> configure the reference, or leave empty if dialog
            should be loaded from url
          </li>
          <li><b>modal-type</b> defines the type of modal</li>
          <li><b>modal-title</b> the title of the modal which is opened</li>
          <li><b>modal-url</b> the url of a view which is referenced and
            included in the modal
          </li>
        </ul>
      </p>
      <button class="btn btn-info" modal="confirmModal" modal-type="confirm" 
        modal-title="Confirm" modal-content="This is the modal content" modal-state="closeModal">Dialog - Confirm</button> 
      <div id="confirmModal">
        <div class="modal-body">
          <p>{{content}}</p>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-primary" ng-click="confirm()">Confirm</a>
        </div>
      </div>
      <button class="btn btn-warning" modal="alertModal" modal-type="confirm" modal-title="Alert">Dialog - Alert</button> 
      <div id="alertModal">
        <div class="modal-body">
          <p>One fine body…</p>
        </div>
        <div class="modal-footer">
          <a href="" class="btn" ng-click="discard()">Discard</a>
          <a href="" class="btn btn-primary" ng-click="ok()">Ok</a>
        </div>
      </div>
      <button class="btn btn-danger" modal="" modal-type="dialog" modal-title="External no url">Dialog - Url Missing</button> 
      <button class="btn btn-success" modal="" modal-type="dialog" modal-title="Add Todo" modal-url="sample.html">Dialog</button>
      
      <br/><br/>
      <p>
        The table below shows the todos added to the list
      </p>
      <table class="table table-bordered table-striped">
        <thead>
          <tr>
            <th>Name</th>
            <th>Due date</th>
            <th>Estimate</th>
            <th>Options</th>
          </tr>
        </thead>
        <tbody>
          <tr ng-show="!todos.length">
            <td colspan="4">No entries yet</td>
          </tr>
          <tr ng-repeat="todo in todos">
            <td>{{todo.name}}</td>
            <td>{{todo.date}}</td>
            <td>{{todo.estimate}}</td>
            <td>
              <button class="btn btn-info" ng-click="edit($index)" modal="" modal-type="dialog" modal-title="Edit Todo" modal-url="sample.html"><i class="icon-white icon-pencil"></i></button>
              <button class="btn btn-danger" ng-click="remove(todo)"><i class="icon-white icon-trash"></i></button>
            </td>
          </tr>
        </tbody>  
      </table>
      <pre>todos = {{todos | json}}</pre>
    </div>
  </body>
</html>

(function(angular) {
  var modalDirective = angular.module('directive.modal', []);

modalDirective.templates = {
  UrlNotDefined : '<div class="modal-body">'
  +                 '<h3>404 - Resource could not be found</h3>'
  +                 '<p>Specified URL <i>({{url}})</i> for Modal <strong>{{id}}</strong> could not be found.</p>'
  +               '</div>'
  +               '<div class="modal-footer">'
  +                 '<button type="button" class="btn btn-primary" ng-click="close()">Close</a>'
  +               '</div>',
  main  : '<div style="position: absolute;" ng-class="{hide: !visible}">'
  +         '<div class="modal-backdrop fade in">'
  +         '</div>'
  +         '<div class="modal" tabindex="-1" role="dialog" aria-labelledby="label" aria-hidden="true">'
  +           '<div class="modal-header">'
  +             '<button type="button" class="close" ng-click="close()">&times;</button>'
  +             '<h1 id="label">{{title}}</h1>'
  +           '</div>'          
  +         '</div>'
  +       '</div>'
}
  
modalDirective.directive('modal', ['$rootScope', '$compile', '$timeout', '$http', function($rootScope, $compile, $timeout, $http) {
  return {
    restrict  : 'A',
    scope     : '=',
    compile: function compile(tElement, tAttrs, transclude) {
      return {          
        post: function postLink(scope, iElement, iAttrs, controller) {
          var modal           = $(modalDirective.templates.main),
              modalContainer  = $('.modal', modal),
              body            = $('#' + iAttrs.modal),
              error           = $(modalDirective.templates.UrlNotDefined),
              type            = iAttrs.modalType,
              url             = iAttrs.modalUrl,
              bodyContainer   = 'body',
              last            = null;
          scope.title       = iAttrs.modalTitle;
          scope.content     = iAttrs.modalContent;
          scope.visible     = false;
          
          body.css({ 'display' : 'none' });
          
          if (type == 'dialog' && url !== undefined) {
            $http.get(url).success(function (data) {
              body = $(data);
            }).error(function (error) {
              scope.title = 'Errro loading contents';
              body = $(error);
            });  
          } else if(type == 'dialog' && url === undefined) {
            scope.title = 'No url provided';
            body = error;
          }
          
          iElement.click(function(event) {              
            open();
          });
          
          var open = function() {
            modalContainer.append(body);
            modal.appendTo(bodyContainer);
            
            scope.visible = true;
            body.css({ 'display' : 'block' });
            
            scope.$apply($compile(modal)(scope));
            
            last = event.timeStamp;
          };

          scope.close = function() {
            scope.$emit('modal', 'close');
          };
          
          var closeModal = function() {
            modal.remove();
          };
          
          scope.$on('modal', function(envelope, data) {  
            if (data === 'close')
              closeModal();
          });
          
          $(bodyContainer).bind('keyup', function(event) {
            if(event.which == 27) {
              closeModal();
            }
          });
           
          $(document).click(function(event) {
            var target = $(event.target);
            if(!target.is(".modal") && !target.parents().is(".modal")) {
              if(last === event.timeStamp)
                return;  
              closeModal();
            }
          });
        }
      };
    }
  };
}]);
})(window.angular);
var app = angular.module('myApp', ['directive.modal']);

app.controller('Controller', function($rootScope, $scope) {
      $scope.todos   = [];
      $scope.todo   = undefined;
      
      $scope.confirm = function () {
        console.log('confirm was clicked');
        $scope.$broadcast('modal', 'close');
      };
      
      $scope.discard = function () {
        console.log('discard was clicked');
        $scope.todo = undefined;
        $scope.$broadcast('modal', 'close');
      };
      
      $scope.ok = function () {
        console.log('ok was clicked');
        $scope.$broadcast('modal', 'close');
      };  
      
      $scope.save = function () {
        console.log('save was clicked');
        
        if ($scope.todos.indexOf($scope.todo) === -1)
          $scope.todos.push($scope.todo);
        
        $scope.todo = undefined;
        $scope.$broadcast('modal', 'close');
      };		
      
      $scope.remove = function (todo) {
        var index = $scope.todos.indexOf(todo);

        $scope.todos.splice(index, 1);
      };
      
      $scope.edit = function (index) {
        $scope.todo = $scope.todos[index];
      };
      
      var modalObject = {
        modal : '',
        modalType : 'dialog',
        modalUrl : 'sample.html',
        modalTitle : 'This is a sample title'
      };
      $scope.modalObject = modalObject;
});

app.controller('ChildController', function($scope) {
  $scope.initDialog = function () {
		if ($scope.$parent.$parent.todo !== undefined) {
			$scope.todo = $scope.$parent.$parent.todo;
		} else {
			$scope.todo = {};
		}
		$scope.$parent.$parent.todo = $scope.todo;
	};
});
<div class="modal-body" ng-controller="ChildController" ng-init="initDialog()">
  <form>
	  <label>Todo title</label>
	  <input type="text" class="input-medium" placeholder="Add Todo.." ng-model="todo.name"> 
	  <label>Todo date</label>
	  <input type="text" class="input-medium" placeholder="Add Todo.." ng-model="todo.date">
	  <label>Todo estimate</label>
	  <input type="text" class="input-medium" placeholder="Add Todo.." ng-model="todo.estimate">      
	</form>  
	</div>
	<div class="modal-footer">
		<a href="" class="btn" ng-click="discard()">Discard</a>
		<a href="" class="btn btn-primary" ng-click="save()">Save changes</a>
	</div>
</div>