Modal service for AngularJS - supports creating popups and modals via a service. Full support for Angular 1.5+ components. See a quick fiddle or a full set of samples at dwmkerr.github.io/angular-modal-service.
Install with Bower (or NPM):
bower install angular-modal-service
# or...
npm install angular-modal-service
Then reference the minified script:
<script src="bower_components/angular-modal-service/dst/angular-modal-service.min.js"></script>
Specify the modal service as a dependency of your application:
var app = angular.module('sampleapp', ['angularModalService']);
Now just inject the modal service into any controller, service or directive where you need it.
app.controller('SampleController', ["$scope", "ModalService", function($scope, ModalService) {
$scope.showAModal = function() {
// Just provide a template url, a controller and call 'showModal'.
ModalService.showModal({
templateUrl: "yesno/yesno.html",
controller: "YesNoController"
}).then(function(modal) {
// The modal object has the element built, if this is a bootstrap modal
// you can call 'modal' to show it, if it's a custom modal just show or hide
// it as you need to.
modal.element.modal();
modal.close.then(function(result) {
$scope.message = result ? "You said Yes" : "You said No";
});
});
};
}]);
Calling showModal
returns a promise which is resolved when the modal DOM element is createdand the controller for it is created. The promise returns a modal
object which contains theelement created, the controller, the scope and two promises: close
and closed
. Both areresolved to the result of the modal close function, but close
is resolved as soon as themodal close function is called, while closed
is only resolved once the modal has finishedanimating and has been completely removed from the DOM.
The modal controller can be any controller that you like, just remember that it is alwaysprovided with one extra parameter - the close
function. Here's an example controllerfor a bootstrap modal:
app.controller('SampleModalController', function($scope, close) {
$scope.dismissModal = function(result) {
close(result, 200); // close, but give 200ms for bootstrap to animate
};
});
The close
function is automatically injected to the modal controller and takes the resultobject (which is passed to the close
and closed
promises used by the caller). It cantake an optional second parameter, the number of milliseconds to wait before destroying theDOM element. This is so that you can have a delay before destroying the DOM element if youare animating the closure. See Global Config for setting a default delay.
Now just make sure the close
function is called by your modal controller when the modalshould be closed and that's it. Quick hint - if you are using Bootstrap for your modals,then make sure the modal template only contains one root level element, see the FAQfor the gritty details of why.
To pass data into the modal controller, use the inputs
field of the modal options. For example:
ModalService.showModal({
templateUrl: "exampletemplate.html",
controller: "ExampleController",
inputs: {
name: "Fry",
year: 3001
}
})
injects the name
and year
values into the controller:
app.controller('ExampleController', function($scope, name, year, close) {
});
You can also provide a controller function directly to the modal, with or without the controllerAs
attribute.But if you provide controller
attribute with as
syntax and controllerAs
attribute together, controllerAs
will have high priority.
ModalService.showModal({
template: "<div>Fry lives in {{futurama.city}}</div>",
controller: function() {
this.city = "New New York";
},
controllerAs : "futurama"
})
It's also possible to specify a component, rather than a template and controller. This can be done by providing a component
and an optional bindings
value to the showModal
function.
ModalService.showModal({
component: 'myComponent',
bindings: {
name: 'Foo',
myRecord: { id: '123' }
}
})
The showModal
function takes an object with these fields:
controller
: The name of the controller to create. It could be a function.controllerAs
: The name of the variable on the scope instance of the controller is assigned to - (optional).templateUrl
: The URL of the HTML template to use for the modal.template
: If templateUrl
is not specified, you can specify template
as rawHTML for the modal.inputs
: A set of values to pass as inputs to the controller. Each value providedis injected into the controller constructor.component
: Renders a modal with the provided component as its templatebindings
: Optional. If component
is provided, all properties in bindings
will be bound to the rendered component
.appendElement
: The custom angular element or selector (such as #element-id
) to append the modal to instead of default body
element.scope
: Optional. If provided, the modal controller will use a new scope as a child of scope
(created by calling scope.$new()
) rather than a new scope created as a child of $rootScope
.bodyClass
: Optional. The custom css class to append to the body while the modal is open (optional, useful when not using Bootstrap).preClose
: Optional. A function which will be called before the process of closing a modal starts. The signature is function preClose(modal, result, delay)
. It is provided the modal
object, the result
which was passed to close
and the delay
which was passed to close.locationChangeSuccess
: Optional. Allows the closing of the modal when the location changes to be configured. If no value is set, the modal is closed immediately when the $locationChangeSuccess
event fires. If false
is set, event is not fired. If a number n
is set, then the event fires after n
milliseconds.The modal
object returned by showModal
has this structure:
modal.element
- The created DOM element. This is a jquery lite object (or jquery if fulljquery is used). If you are using a bootstrap modal, you can call modal
on this objectto show the modal.modal.scope
- The new scope created for the modal DOM and controller.modal.controller
- The new controller created for the modal.modal.close
- A promise which is resolved when the modal close
function is called.modal.closed
- A promise which is resolved once the modal has finished animating out of the DOM.The controller that is used for the modal always has one extra parameter injected, a functioncalled close
. Call this function with any parameter (the result). This result parameter isthen passed as the parameter of the close
and closed
promises used by the caller.
Sometimes you may way to forcibly close all open modals, for example if you are going to transition routes. You can use the ModalService.closeModals
function for this:
ModalService.closeModals(optionalResult, optionalDelay);
The optionalResult
parameter is pased into all close
promises, the optionalDelay
parameter has the same effect as the controller close
function delay parameter.
ModalService
cooperates with Angular's $animate
service to allow easy implementation ofcustom animation. Specifically, showModal
will trigger the ng-enter
hook, and callingclose
will trigger the ng-leave
hook. For example, if the ngAnimate
module isinstalled, the following CSS rules will add fade in/fade out animations to a modal with theclass modal
:
.modal.ng-enter {
transition: opacity .5s ease-out;
opacity: 0;
}
.modal.ng-enter.ng-enter-active {
opacity: 1;
}
.modal.ng-leave {
transition: opacity .5s ease-out;
opacity: 1;
}
.modal.ng-leave.ng-leave-active {
opacity: 0;
}
As the ModalService
exposes only one function, showModal
, error handling is always performed in the same way.The showModal
function returns a promise - if any part of the process fails, the promise will be rejected, meaningthat a promise error handling function or catch
function can be used to get the error details:
ModalService.showModal({
templateUrl: "some/template.html",
controller: "SomeController"
}).then(function(modal) {
// only called on success...
}).catch(function(error) {
// error contains a detailed error message.
console.log(error);
});
To configure the default options that will apply to all modals call configureOptions
on the ModalServiceProvider
.
app.config(["ModalServiceProvider", function(ModalServiceProvider) {
ModalServiceProvider.configureOptions({closeDelay:500});
}]);
Here are the available global options:
closeDelay
- This sets the default number of milliseconds to use in the close handler. This delay will also be used in the closeModals
method and as the default for locationChangeSuccess
.To work with the code, just run:
npm install
npm test
npm start
The dependencies will install, the tests will be run (always a useful sanity check after a clean checkout) and the code will run. You can open the browser at localhost:8080 to see the samples. As you change the code in the src/
folder, it will be re-built and the browser will be updated.
The easiest way to adapt the code is to play with some of the examples in the samples
folder.
Run tests with:
npm test
A coverage report is written to build\coverage
.
Debug tests with:
npm run test-debug
This will run the tests in Chrome, allowing you to debug.
To create a release:
dst
pack with npm run build
npm run release
to tag, bump the version numbers and update the changeloggit push --follow-tags && npm publish
Having problems? Check this FAQ first.
I'm using a Bootstrap Modal and the backdrop doesn't fade away
This can happen if your modal template contains more than one top level element.Imagine this case:
<!-- Some comment -->
<div>...some modal</div>
When you create the modal, the Angular Modal Service will add both of these elementsto the page, then pass the elements to you as a jQuery selector. When you call bootstrap'smodal
function on it, like this:
modal.element.modal();
It will try and make both elements into a modal. This means both elements will get a backdrop.In this case, either remove the extra elements, or find the specific element you needfrom the provided modal.element
property.
The backdrop STILL does not fade away after I call close
OR I don't want to use the 'data-dismiss' attribute on a button, how can I close a modal manually?
You can check the 'Complex' sample (complexcontroller.js). The 'Cancel' button closes without using the data-dismiss
attribute. In this case, just use the preClose
option to ensure the bootstrap modal is removed:
ModalService.showModal({
templateUrl: "some/bootstrap-template.html",
controller: "SomeController",
preClose: (modal) => { modal.element.modal('hide'); }
}).then(function(modal) {
// etc
});
Another option is to grab the modal element in your controller, then call the bootstrap modal
functionto manually close the modal. Then call the close
function as normal:
app.controller('ExampleModalController', [
'$scope', '$element', 'close',
function($scope, $element, close) {
$scope.closeModal = function() {
// Manually hide the modal using bootstrap.
$element.modal('hide');
// Now close as normal, but give 500ms for bootstrap to animate
close(null, 500);
};
}]);
I'm using a Bootstrap Modal and the dialog doesn't show up
Code is entered exactly as shown the example but when the showAModal() function fires the modal template html is appended to the body while the console outputs:
TypeError: undefined is not a function
Pointing to the code: modal.element.modal();
. This occurs if you are using a Bootstap modal but have not included the Bootstrap JavaScript. The recommendation is to include the modal JavaScript before AngularJS.
How can I prevent a Bootstrap modal from being closed?
If you are using a bootstrap modal and want to make sure that only the close
function will close the modal (not a click outside or escape), use the following attributes:
<div class="modal" data-backdrop="static" data-keyboard="false">
To do this programatically, use:
ModalService.showModal({
templateUrl: "whatever.html",
controller: "WhateverController"
}).then(function(modal) {
modal.element.modal({
backdrop: 'static',
keyboard: false
});
modal.close.then(function(result) {
// ...etc
});
});
Thanks lindamarieb and ledgeJumper!
Problems with Nested Modals
If you are trying to nest Bootstrap modals, you will run into issues. From Bootstrap:
Bootstrap only supports one modal window at a time. Nested modals aren’t supported as we believe them to be poor user experiences.
See: https://v4-alpha.getbootstrap.com/components/modal/#how-it-works
Some people have been able to get them working (see https://github.com/dwmkerr/angular-modal-service/issues/176). Unfortunately, due to the lack of support in Bootstrap is has proven troublesome to support this in angular-modal-service.
Thanks go the the following contributors:
$templateCache
.body
element changes.bodyClass
feature.appendElement
improvements.这篇文章其实写的有点晚了。去年6月份,Angular2的版本刚升级到rc-4,一切都还处于蛮荒时期(虽然现在依然不是太稳定...)。当时为我们的组件库开发Modal组件,因为严格遵守ant design的规范来开发,所以Modal包含了Directive和Service两种模式 Directive模式非常符合Angular2的设计思想,所以开发过程也是顺风顺水。使用的方
因为记性不好的原因做个草稿笔记 app.js中 var myApp = angular.module('myApp',['ui.router','oc.lazyLoad','ngAnimate','数据处理','公共js方法']); 注册权限访问服务 myApp.factory('$permissions',['$rootScope','$es',function($rootScope,$
最近的一个新需求就是需要把ant-design-angular的弹窗实现拖拽,我们当初写的时候都是用service注入的方式来实现弹窗,在网上找成品轮子时发现都是针对使用非服务方式创建的(给标签添加指令),记录一下实现方式。 中心的实现思想就是利用服务把事件绑定在modal的header上,通过控制’mousedowm’,‘mouseup’,‘mousemove’,来实现拖拽。 具体实现如下: i
定义一个弹出框的服务:alert_box defiine(["app"],function(mainapp){ mainapp.controller('ModalInstanceCtrl',[ "$scope","$uibModalInstance","items",function ($scope, $uibModalInstance, items) { $scope.items =
今天遇到一个问题,在modal中写了一个form,提交到数据库后需要刷新页面,但ng-bootstrap的modal就是没有事件输出,热心的小伙伴提醒可以写个service来传递事件,不多说了直接上代码: service: import {EventEmitter, Injectable} from '@angular/core'; @Injectable() export class Moda
最近在项目中有需求可以拖拽的弹窗,网上搜索了一遍都是服务端创建的弹窗可拖拽,而通过template创建的弹窗确比较难实现,我参考了别人的实现,改造了一下,就可以实现template的拖拽。 1. 创建指令 drag-modal.directive.ts import { Directive, ElementRef, Input } from '@angular/core'; import { Mo
问题内容: 我在尝试为Angular-Bootstrap编写茉莉花单元测试时遇到问题 。确切的错误是 `Expected spy open to have been called with [ { templateUrl : ‘/n/views/consent.html’, controller : ‘W2ConsentModal as w2modal’, resolve : { employee
问题内容: 我添加了一个Angular UI Modal,将范围传递给Modal Window进行2种方式绑定。我使用了该方法来传递范围值。这样做可以起到一定的作用,这意味着当ng- model值在父级中更改时,它会在模态窗口内反映出来。但是,如果值在模态窗口内更改,则不会在父ng模型中反映出来。这是我的代码: HTML: 控制器: 为什么在上面的代码中isint父实例和模态实例之间的2种方式绑定
模态是在其父窗口上分层的子窗口。 通常,目的是显示来自单独源的内容,该源可以在不离开父窗口的情况下进行一些交互。 子窗口可以提供信息,交互等。 如果您想单独包含此插件功能,那么您将需要modal.js 。 另外,如Bootstrap插件概述一章所述,您可以包含bootstrap.js或缩小的bootstrap.min.js 。 用法 (Usage) 您可以切换模态插件的隐藏内容 - Via dat
Modal 是从App的主要内容区域上弹出的一小块内容块. Modals经常被用来向用户询问信息,或通知或警告用户。 Modal和其他所有的遮罩图层一样,是所谓的“临时视图”的一部分。 Modals 可以只用JavaScript打开。所以让我们来看看使用modals的相关APP方法 预定义的 Modals 注意,如果你没有指定预定义的modal标题,它讲使用默认的标题("Framework7"),
描述 Modal 提供了弹出遮罩层的能力,为 Alert, Confirm 等对话框组件提供了底层能力。 安装 $ npm install rax-modal --save 属性 属性 类型 默认值 必填 描述 支持 visible boolean - ✘ 控制弹层是否显示 contentStyle Object - ✘ 自定义内容容器样式 maskStyle Object - ✘ 自定义弹层样式
modal 模块提供了以下展示消息框的 API:toast、alert、confirm 和 prompt。 toast toast() 会在一个小浮层里展示关于某个操作的简单反馈。例如,在邮件发送前离开邮件编辑界面,可以触发一个“草稿已保存”的 toast,告知用户以后可以继续编辑。toast 会在显示一段时间之后自动消失。 toast(options) @options message, str