├── test-page ├── index.view.html └── index.controller.js ├── README.md ├── _content ├── app.less └── modal.less ├── home ├── index.controller.js └── index.view.html ├── app.js ├── LICENSE ├── _services └── modal.service.js ├── index.html └── _directives └── modal.directive.js /test-page/index.view.html: -------------------------------------------------------------------------------- 1 |
2 |

Test Page

3 |

This one doesn't have any modals...

4 |
-------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | angularjs-custom-modal-example 2 | ============================== 3 | 4 | AngularJS Custom Modal Example & Tutorial 5 | 6 | To see a demo and further details go to http://jasonwatmore.com/post/2016/07/13/angularjs-custom-modal-example-tutorial 7 | -------------------------------------------------------------------------------- /test-page/index.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app') 6 | .controller('TestPage.IndexController', Controller); 7 | 8 | function Controller() { 9 | var vm = this; 10 | 11 | initController(); 12 | 13 | function initController() { 14 | } 15 | } 16 | 17 | })(); -------------------------------------------------------------------------------- /_content/app.less: -------------------------------------------------------------------------------- 1 | /* EXAMPLE STYLES 2 | -------------------------------*/ 3 | body { 4 | font-family: roboto; 5 | padding: 20px; 6 | } 7 | 8 | nav { 9 | margin-bottom: 20px; 10 | padding-bottom: 20px; 11 | border-bottom: 1px solid #ddd; 12 | 13 | a { 14 | margin-right: 8px; 15 | } 16 | } 17 | 18 | h1 { 19 | font-weight: normal; 20 | margin-top: 0; 21 | } 22 | 23 | input[type="text"] { 24 | display:block; 25 | width: 100%; 26 | font-family: roboto; 27 | } 28 | 29 | .credits { 30 | margin-top: 30px; 31 | border-top: 1px solid #ddd; 32 | text-align: center; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /home/index.controller.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app') 6 | .controller('Home.IndexController', Controller); 7 | 8 | function Controller(ModalService) { 9 | var vm = this; 10 | 11 | vm.openModal = openModal; 12 | vm.closeModal = closeModal; 13 | 14 | initController(); 15 | 16 | function initController() { 17 | vm.bodyText = 'This text can be updated in modal 1'; 18 | } 19 | 20 | function openModal(id){ 21 | ModalService.Open(id); 22 | } 23 | 24 | function closeModal(id){ 25 | ModalService.Close(id); 26 | } 27 | } 28 | 29 | })(); -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app', ['ui.router']) 6 | .config(config) 7 | .run(run); 8 | 9 | function config($stateProvider, $urlRouterProvider) { 10 | // default route 11 | $urlRouterProvider.otherwise("/"); 12 | 13 | // app routes 14 | $stateProvider 15 | .state('home', { 16 | url: '/', 17 | templateUrl: 'home/index.view.html', 18 | controller: 'Home.IndexController', 19 | controllerAs: 'vm' 20 | }) 21 | .state('test-page', { 22 | url: '/test-page', 23 | templateUrl: 'test-page/index.view.html', 24 | controller: 'TestPage.IndexController', 25 | controllerAs: 'vm' 26 | }); 27 | } 28 | 29 | function run() { 30 | } 31 | })(); -------------------------------------------------------------------------------- /home/index.view.html: -------------------------------------------------------------------------------- 1 |
2 |

Home

3 |

{{vm.bodyText}}

4 | 5 | 6 |
7 | 8 | 9 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jason Watmore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /_services/modal.service.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app') 6 | .factory('ModalService', Service); 7 | 8 | function Service() { 9 | var modals = []; // array of modals on the page 10 | var service = {}; 11 | 12 | service.Add = Add; 13 | service.Remove = Remove; 14 | service.Open = Open; 15 | service.Close = Close; 16 | 17 | return service; 18 | 19 | function Add(modal) { 20 | // add modal to array of active modals 21 | modals.push(modal); 22 | } 23 | 24 | function Remove(id) { 25 | // remove modal from array of active modals 26 | var modalToRemove = _.findWhere(modals, { id: id }); 27 | modals = _.without(modals, modalToRemove); 28 | } 29 | 30 | function Open(id) { 31 | // open modal specified by id 32 | var modal = _.findWhere(modals, { id: id }); 33 | modal.open(); 34 | } 35 | 36 | function Close(id) { 37 | // close modal specified by id 38 | var modal = _.findWhere(modals, { id: id }); 39 | modal.close(); 40 | } 41 | } 42 | 43 | })(); 44 | -------------------------------------------------------------------------------- /_content/modal.less: -------------------------------------------------------------------------------- 1 | /* MODAL STYLES 2 | -------------------------------*/ 3 | modal { 4 | /* modals are hidden by default */ 5 | display: none; 6 | 7 | .modal { 8 | /* modal container fixed across whole screen */ 9 | position: fixed; 10 | top: 0; 11 | right: 0; 12 | bottom: 0; 13 | left: 0; 14 | 15 | /* z-index must be higher than .modal-background */ 16 | z-index: 1000; 17 | 18 | /* enables scrolling for tall modals */ 19 | overflow: auto; 20 | 21 | .modal-body { 22 | padding: 20px; 23 | background: #fff; 24 | 25 | /* margin exposes part of the modal background */ 26 | margin: 40px; 27 | } 28 | } 29 | 30 | .modal-background { 31 | /* modal background fixed across whole screen */ 32 | position: fixed; 33 | top: 0; 34 | right: 0; 35 | bottom: 0; 36 | left: 0; 37 | 38 | /* semi-transparent black */ 39 | background-color: #000; 40 | opacity: 0.75; 41 | 42 | /* z-index must be below .modal and above everything else */ 43 | z-index: 900; 44 | } 45 | } 46 | 47 | body.modal-open { 48 | /* body overflow is hidden to hide main scrollbar when modal window is open */ 49 | overflow: hidden; 50 | } 51 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AngularJS Custom Modal Example & Tutorial 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 19 | 20 |
21 | 22 | 23 |
24 |

25 | AngularJS Custom Modal Example & Tutorial 26 |

27 |

28 | JasonWatmore.com 29 |

30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /_directives/modal.directive.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | angular 5 | .module('app') 6 | .directive('modal', Directive); 7 | 8 | function Directive(ModalService) { 9 | return { 10 | link: function (scope, element, attrs) { 11 | // ensure id attribute exists 12 | if (!attrs.id) { 13 | console.error('modal must have an id'); 14 | return; 15 | } 16 | 17 | // move element to bottom of page (just before ) so it can be displayed above everything else 18 | element.appendTo('body'); 19 | 20 | // close modal on background click 21 | element.on('click', function (e) { 22 | var target = $(e.target); 23 | if (!target.closest('.modal-body').length) { 24 | scope.$evalAsync(Close); 25 | } 26 | }); 27 | 28 | // add self (this modal instance) to the modal service so it's accessible from controllers 29 | var modal = { 30 | id: attrs.id, 31 | open: Open, 32 | close: Close 33 | }; 34 | ModalService.Add(modal); 35 | 36 | // remove self from modal service when directive is destroyed 37 | scope.$on('$destroy', function() { 38 | ModalService.Remove(attrs.id); 39 | element.remove(); 40 | }); 41 | 42 | // open modal 43 | function Open() { 44 | element.show(); 45 | $('body').addClass('modal-open'); 46 | } 47 | 48 | // close modal 49 | function Close() { 50 | element.hide(); 51 | $('body').removeClass('modal-open'); 52 | } 53 | } 54 | }; 55 | } 56 | })(); --------------------------------------------------------------------------------