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

Commit

Permalink
fix(Modal): Use attribute observe and add a render promise.
Browse files Browse the repository at this point in the history
  • Loading branch information
zaknuces authored and wesleycho committed Mar 16, 2015
1 parent b5a80c0 commit 99af5f8
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/modal/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The `open` method returns a modal instance, an object with the following propert
* `dismiss(reason)` - a method that can be used to dismiss a modal, passing a reason
* `result` - a promise that is resolved when a modal is closed and rejected when a modal is dismissed
* `opened` - a promise that is resolved when a modal gets opened after downloading content's template and resolving all variables
* 'rendered' - a promise that is resolved when a modal is rendered.

In addition the scope associated with modal's content is augmented with 2 methods:

Expand Down
50 changes: 41 additions & 9 deletions src/modal/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
};
}])

.directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
.directive('modalWindow', ['$modalStack', '$q', function ($modalStack, $q) {
return {
restrict: 'EA',
scope: {
Expand All @@ -91,7 +91,31 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
element.addClass(attrs.windowClass || '');
scope.size = attrs.size;

$timeout(function () {
scope.close = function (evt) {
var modal = $modalStack.getTop();
if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
evt.preventDefault();
evt.stopPropagation();
$modalStack.dismiss(modal.key, 'backdrop click');
}
};

// This property is only added to the scope for the purpose of detecting when this directive is rendered.
// We can detect that by using this property in the template associated with this directive and then use
// {@link Attribute#$observe} on it. For more details please see {@link TableColumnResize}.
scope.$isRendered = true;

// Deferred object that will be resolved when this modal is render.
var modalRenderDeferObj = $q.defer();
// Observe function will be called on next digest cycle after compilation, ensuring that the DOM is ready.
// In order to use this way of finding whether DOM is ready, we need to observe a scope property used in modal's template.
attrs.$observe('modalRender', function (value) {
if (value == 'true') {
modalRenderDeferObj.resolve();
}
});

modalRenderDeferObj.promise.then(function () {
// trigger CSS transitions
scope.animate = true;

Expand All @@ -106,16 +130,13 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
if (!element[0].querySelectorAll('[autofocus]').length) {
element[0].focus();
}
});

scope.close = function (evt) {
// Notify {@link $modalStack} that modal is rendered.
var modal = $modalStack.getTop();
if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
evt.preventDefault();
evt.stopPropagation();
$modalStack.dismiss(modal.key, 'backdrop click');
if (modal) {
$modalStack.modalRendered(modal.key);
}
};
});
}
};
}])
Expand Down Expand Up @@ -236,6 +257,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])

openedWindows.add(modalInstance, {
deferred: modal.deferred,
renderDeferred: modal.renderDeferred,
modalScope: modal.scope,
backdrop: modal.backdrop,
keyboard: modal.keyboard
Expand Down Expand Up @@ -296,6 +318,13 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
return openedWindows.top();
};

$modalStack.modalRendered = function (modalInstance) {
var modalWindow = openedWindows.get(modalInstance);
if (modalWindow) {
modalWindow.value.renderDeferred.resolve();
}
};

return $modalStack;
}])

Expand Down Expand Up @@ -333,11 +362,13 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])

var modalResultDeferred = $q.defer();
var modalOpenedDeferred = $q.defer();
var modalRenderDeferred = $q.defer();

//prepare an instance of a modal to be injected into controllers and returned to a caller
var modalInstance = {
result: modalResultDeferred.promise,
opened: modalOpenedDeferred.promise,
rendered: modalRenderDeferred.promise,
close: function (result) {
$modalStack.close(modalInstance, result);
},
Expand Down Expand Up @@ -385,6 +416,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
$modalStack.open(modalInstance, {
scope: modalScope,
deferred: modalResultDeferred,
renderDeferred: modalRenderDeferred,
content: tplAndVars[0],
backdrop: modalOptions.backdrop,
keyboard: modalOptions.keyboard,
Expand Down
8 changes: 5 additions & 3 deletions src/modal/test/modalWindow.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@ describe('modal window', function () {
}));

it('should not use transclusion scope for modals content - issue 2110', function () {
$compile('<div modal-window><span ng-init="foo=true"></span></div>')($rootScope);
$rootScope.animate = false;
$compile('<div modal-window animate="animate"><span ng-init="foo=true"></span></div>')($rootScope);
$rootScope.$digest();

expect($rootScope.foo).toBeTruthy();
});

it('should support custom CSS classes as string', function () {
var windowEl = $compile('<div modal-window window-class="test foo">content</div>')($rootScope);
$rootScope.animate = false;
var windowEl = $compile('<div modal-window animate="animate" window-class="test foo">content</div>')($rootScope);
$rootScope.$digest();

expect(windowEl).toHaveClass('test');
Expand All @@ -33,4 +35,4 @@ describe('modal window', function () {
expect(windowEl).toHaveClass('mywindow');
expect(windowEl).toHaveClass('test');
}));
});
});
4 changes: 2 additions & 2 deletions template/modal/window.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<div tabindex="-1" role="dialog" class="modal fade" ng-class="{in: animate}" ng-style="{'z-index': 1050 + index*10, display: 'block'}" ng-click="close($event)">
<div modal-render="{{$isRendered}}" tabindex="-1" role="dialog" class="modal fade" ng-class="{in: animate}" ng-style="{'z-index': 1050 + index*10, display: 'block'}" ng-click="close($event)">
<div class="modal-dialog" ng-class="{'modal-sm': size == 'sm', 'modal-lg': size == 'lg'}"><div class="modal-content" modal-transclude></div></div>
</div>
</div>

0 comments on commit 99af5f8

Please sign in to comment.