Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
feat(modal): add appendTo support
Browse files Browse the repository at this point in the history
- Add support for appending to specific element through `appendTo` option

Closes #4599
  • Loading branch information
aroop authored and wesleycho committed Oct 28, 2015
1 parent 8ffdaeb commit 16d854c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/modal/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The `$uibModal` service has only one method: `open(options)` where available opt
* `windowTemplateUrl` - a path to a template overriding modal's window template
* `size` - optional suffix of modal window class. The value used is appended to the `modal-` class, i.e. a value of `sm` gives `modal-sm`
* `openedClass` - class added to the `body` element when the modal is opened. Defaults to `modal-open`
* `appendTo` - Appends the modal to a specific element. appendTo must be an `angular.element`. Defaults to `body` element. Example: `appendTo: $document.find('aside')`.

Global defaults may be set for `$uibModal` via `$uibModalProvider.options`.

Expand Down
25 changes: 16 additions & 9 deletions src/modal/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,16 +280,16 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
});

function removeModalWindow(modalInstance, elementToReceiveFocus) {
var body = $document.find('body').eq(0);
var modalWindow = openedWindows.get(modalInstance).value;
var appendToElement = $document.find(modalWindow.appendTo).eq(0);

//clean up the stack
openedWindows.remove(modalInstance);

removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, function() {
var modalBodyClass = modalWindow.openedClass || OPENED_MODAL_CLASS;
openedClasses.remove(modalBodyClass, modalInstance);
body.toggleClass(modalBodyClass, openedClasses.hasKey(modalBodyClass));
appendToElement.toggleClass(modalBodyClass, openedClasses.hasKey(modalBodyClass));
toggleTopWindowClass(true);
});
checkRemoveBackdrop();
Expand All @@ -298,7 +298,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
if (elementToReceiveFocus && elementToReceiveFocus.focus) {
elementToReceiveFocus.focus();
} else {
body.focus();
appendToElement.focus();
}
}

Expand Down Expand Up @@ -418,14 +418,19 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
keyboard: modal.keyboard,
openedClass: modal.openedClass,
windowTopClass: modal.windowTopClass,
animation: modal.animation
animation: modal.animation,
appendTo: modal.appendTo
});

openedClasses.put(modalBodyClass, modalInstance);

var body = $document.find('body').eq(0),
var appendToElement = $document.find(modal.appendTo).eq(0),
currBackdropIndex = backdropIndex();

if (!appendToElement.length) {
throw new Error('appendTo element not found. Make sure that the element passed is in DOM.');
}

if (currBackdropIndex >= 0 && !backdropDomEl) {
backdropScope = $rootScope.$new(true);
backdropScope.modalOptions = modal;
Expand All @@ -436,7 +441,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
angularBackgroundDomEl.attr('modal-animation', 'true');
}
backdropDomEl = $compile(angularBackgroundDomEl)(backdropScope);
body.append(backdropDomEl);
appendToElement.append(backdropDomEl);
}

var angularDomEl = angular.element('<div uib-modal-window="modal-window"></div>');
Expand All @@ -455,8 +460,8 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
var modalDomEl = $compile(angularDomEl)(modal.scope);
openedWindows.top().value.modalDomEl = modalDomEl;
openedWindows.top().value.modalOpener = modalOpener;
body.append(modalDomEl);
body.addClass(modalBodyClass);
appendToElement.append(modalDomEl);
appendToElement.addClass(modalBodyClass);

$modalStack.clearFocusListCache();
};
Expand Down Expand Up @@ -609,6 +614,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
//merge and clean up options
modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
modalOptions.resolve = modalOptions.resolve || {};
modalOptions.appendTo = modalOptions.appendTo || 'body';

//verify options
if (!modalOptions.template && !modalOptions.templateUrl) {
Expand Down Expand Up @@ -675,7 +681,8 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
windowClass: modalOptions.windowClass,
windowTemplateUrl: modalOptions.windowTemplateUrl,
size: modalOptions.size,
openedClass: modalOptions.openedClass
openedClass: modalOptions.openedClass,
appendTo: modalOptions.appendTo
});
modalOpenedDeferred.resolve(true);

Expand Down
42 changes: 42 additions & 0 deletions src/modal/test/modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,48 @@ describe('$uibModal', function () {
expect($document.find('.modal-backdrop')).not.toHaveClass('fade');
});
});

describe('appendTo', function() {
it('should be added to body by default', function() {
var modal = open({template: '<div>Content</div>'});

expect($document).toHaveModalsOpen(1);
expect($document).toHaveModalOpenWithContent('Content', 'div');
});

it('should not be added to body if appendTo is passed', function() {
var element = angular.element('<section>Some content</section>');
angular.element(document.body).append(element);

var modal = open({template: '<div>Content</div>', appendTo: element});

expect($document).not.toHaveModalOpenWithContent('Content', 'div');
});

it('should be added to appendTo element if appendTo is passed', function() {
var element = angular.element('<section>Some content</section>');
angular.element(document.body).append(element);

expect($document.find('section').children('div.modal').length).toBe(0);
open({template: '<div>Content</div>', appendTo: element});
expect($document.find('section').children('div.modal').length).toBe(1);
});

it('should throw error if appendTo element is not found', function() {
expect(function(){
open({template: '<div>Content</div>', appendTo: $document.find('aside')});
}).toThrow(new Error('appendTo element not found. Make sure that the element passed is in DOM.'));
});

it('should be removed from appendTo element when dismissed', function() {
var modal = open({template: '<div>Content</div>'});

expect($document).toHaveModalsOpen(1);

dismiss(modal);
expect($document).toHaveModalsOpen(0);
});
});

describe('openedClass', function() {
var body;
Expand Down

0 comments on commit 16d854c

Please sign in to comment.