Edit in JSFiddle

'use strict';

/**
* http://www.hiddentao.com/archives/2013/11/04/an-improved-angular-module-split-your-modules-into-multiple-files/
* Workaround to make defining and retrieving angular modules easier and more intuitive.
* WM: NB this also will prevent 'module not found error' by always creating a module
* if it does not already exist, but also allowing more dependencies to be added.
*/

(function(angular) {
  var origMethod = angular.module;

  var alreadyRegistered = {};

  /**
  * Register/fetch a module.
  *
  * @param name {string} module name.
  * @param reqs {array} list of modules this module depends upon.
  * @param configFn {function} config function to run when module loads (only applied for the first call to create this module).
  * @returns {*} the created/existing module.
  */
  angular.module = function(name, reqs, configFn) {
    //WM added for debugging
    var isReqs = (reqs && reqs.length !== undefined);
    reqs = reqs || [];
    var module = null;

    //debugger
    //console.log('*&*&*&*&*&*&*&*&', (isReqs ? 'initing' : 'accessing'), 'module', name);

    if (alreadyRegistered[name]) {
      module = origMethod(name);
      module.requires.push.apply(module.requires, reqs);
    } else {
      module = origMethod(name, reqs, configFn);
      alreadyRegistered[name] = module;
    }

    return module;
  };

})(angular);

//************************************************

angular.module('modalDemo', ['modalComp'])
.controller('modalDemoCtrl',
                            [
                            '$scope',
                            'ModalService',
                            function (
                              $scope,
                              ModalService
                            ) {

            //config attached to modal OK button click events
            $scope.modalOKConfig = null;

            $scope.launchModal = function(contentId, targetId, cancellable){
              $scope.modalOKConfig = null;
              targetId = targetId || 0;
              cancellable = cancellable || false;
              var config = { contentId:contentId, targetId:targetId, cancellable:cancellable };
              ModalService.show(config);
            };

            //listen for all modal OK click events, broadcast from the $rootScope downwards
            $scope.$on(
              'modalOKClickEvent',
              function(event, config){
                //bind the OK click event config
                $scope.modalOKConfig = config;
              });

}]);

angular.module('modalComp')
.directive('modal', function($rootScope) {
  return {
    restrict: 'EA',
    scope: {},
    transclude: true,
    controller: function($scope, ModalService){
      //putting the data/service in the $scope directly, Angular will handle changes for you.
      $scope.service = ModalService;
      //service api for simpleModalContent child directives
      this.getService = function(){
        return $scope.service;
      };
    },
    link: function(scope, element, attrs) {
      scope.okButtonClick = function(){
        //broadcast ok event from root with clone of service.config
        $rootScope.$broadcast(
          'modalOKClickEvent',
          _.clone(scope.service.config));

        //reset values in the service
        scope.service.reset();
      };

    },
    template: '<div class="modal" ng-show="service.shown">' +
                '<div class="modal-overlay" ng-click="service.reset()"></div>' +
                '<div class="modal-dialog">' +
                  '<div class="modal-close" ng-click="service.reset()">x</div>' +
                  '<div class="modal-dialog-content" ng-transclude></div>' +
                  '<div class="modal-buttons">' +
                    '<a class="modal-button" ng-click="okButtonClick()">OK</a>' +
                    '<a class="modal-button" ng-click="service.reset()" ng-show="service.cancellable">Cancel</a>' +
                  '</div>' +
                '</div>' +
              '</div>'
  };
})
.directive('modalContent', function() {
  return {
    require: '^modal',
    restrict: 'E',
    transclude: true,
    scope: {},
    link: function(scope, element, attrs, modalCtrl) {
      //bind the service variable to the service exposed
      //by the parent directive - this is more encapsulated
      scope.service = modalCtrl.getService();
      scope.props = {
        contentId: element[0].id
      };
    },
    template: '<div class="modal-content" '+
    'ng-show="service.config.contentId === props.contentId" '+
    'ng-transclude></div>'
  };
});

angular.module('modalComp')
  .factory('ModalService', function () {

    var showModal = function(config) {
      self.config = config;
      self.shown = true;
      self.cancellable = config.cancellable || false;
    };

    var resetModal = function(){
      self.shown = false;
      self.config = null;
      self.cancellable = false;
    };

    var self = {
      show: showModal,
      reset: resetModal
    };

    self.reset();

    return self;
  });

<div ng-app="modalDemo" ng-cloak>
    <h3>Angular Modal Demo</h3>
    <!-- Modal demo UI -->
    <div ng-controller="modalDemoCtrl" class="demo-ui-container">
        <div class="dash-button" ng-click="launchModal('emailIntercept', 1)">Launch Modal 1</div>
        <div class="clearfix"></div><br>
        <div class="dash-button" ng-click="launchModal('wipeHardDrive', 2, true)">Launch Modal 2</div>
        <div class="clearfix"></div><br>
        <p ng-show='modalOKConfig !== null'> Received OK from modal with contentId: <span>{{modalOKConfig.contentId}}</span> and targetId: <span>{{modalOKConfig.targetId}}</span></p>
    </div>
    <!-- Concrete modal directive -->
    <modal>
        <modal-content id="emailIntercept">
            Your emails are being intercepted.
        </modal-content>
        <modal-content id="wipeHardDrive">
            Are you sure you want to wipe your hard drive?
        </modal-content>
    </modal>
</div>
/**********************************/
/*Meyer reset*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
 /*HTML5 display-role reset for older browsers*/
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}
/*Apply a natural box layout model to all elements*/
/*from: http://www.paulirish.com/2012/box-sizing-border-box-ftw/*/
*, *:before, *:after {
  -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
}

/**********************************/
/*Base css styles for simple demos*/

/*Layout*/
body {
  margin:50px 0px; padding:0px;
  text-align:center;
  background: #ddd;
}

.demo-ui-container {
  width:300px;
  margin:0px auto;
  text-align:left;
  padding:15px;
  border:1px dashed #333;
  background-color:#eee;
}

/*Text*/
html {
  color: #444;
  font-size: 16px;
  line-height: 1.4;
  font-family: Helvetica, Arial, sans-serif;;
  font-weight: 300;
}

h1, h2, h3, h4, h5, h6 {
  font-family: Helvetica, Arial, sans-serif;;
  font-weight: 400;
  margin-top: 0.3em;
  margin-bottom: 0.3em;
  color: #333;
}
h1 {font-size: 2.4rem;}
h2 {font-size: 2rem;}
h3 {font-size: 1.6rem;}

hr {border-top: 1px dashed #ccc;}

a, a:link {
  color: #7ba2ac;
  cursor: pointer;
}

a:hover, a:active {
  color: #5e6b6e;
}

.demo-ui-container p > span{
  font-style: italic;
  font-weight: bold;
}

/*Button*/
.dash-button {
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  -ms-border-radius: 4px;
  -o-border-radius: 4px;
  border-radius: 4px;
  display: inline-block;
  cursor: pointer;
  padding: .2em .7em;
  text-align: center;
  color: #999;
  font-weight: bold;
  font-size: 0.85em;
  border: none;
  background-color: #ccc;
  text-shadow: 0 1px 0 rgba(0,0,0,0.1);
  box-shadow: 0 2px 0 -1px rgba(0,0,0,0.03);
}

.dash-button:hover {
  color: #fff;
  background-color: #999;
  box-shadow: 0 2px 0 -1px rgba(0,0,0,0.06);
}

.dash-button:focus {
  outline: 0;
}

/*Nicolas Gallagher's micro clearfix hack*/
/*http://nicolasgallagher.com/micro-clearfix-hack/*/
.clearfix:before,
.clearfix:after {
  content: " ";
  display: table;
}

.clearfix:after {
  clear: both;
}

/*Angular*/
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;
}

/**********************************/
/*Modal css*/

.modal-overlay {
  /* A dark translucent div that covers the whole screen */
  position:absolute;
  z-index:9999;
  top:0;
  left:0;
  width:100%;
  height:100%;
  background-color:#000000;
  opacity: 0.5;
}
.modal-dialog {
  /* A centered div above the overlay with a box shadow. */
  z-index:10000;
  position: absolute;
  width: 25%; /* Default */

  /* Center the dialog */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
  -moz-transform: translate(-50%, -50%);

  background-color: #fff;
  box-shadow: 4px 4px 80px #000;
}
.modal-dialog-content {
  padding:10px;
  text-align: left;
}
.modal-close {
  position: absolute;
  top: 3px;
  right: 5px;
  padding: 5px;
  cursor: pointer;
  font-size: 120%;
  display: inline-block;
  font-weight: bold;
  font-family: 'arial', 'sans-serif';
}
.modal-buttons{
  padding: 5px 10px;
  background: cadetblue;
  text-align: center;
  width: 100%;
}
.modal-button{
  display: inline-block;
  padding: 0.2em 0.8em;
  cursor: pointer;
  color:white;
}
.modal-content{
  padding: 10px;
}