Skip to content

Commit

Permalink
feat(modal): add scrollable option (#2909)
Browse files Browse the repository at this point in the history
Introduces the new modal feature behind twbs/bootstrap#27769.
Setting the option `scrollable: true` will add the corresponding bootstrap class `.modal-dialog-scrollable`
  • Loading branch information
kukac7 authored and Benoit Charbonnier committed Jun 24, 2019
1 parent 0eff381 commit 74fb795
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 2 deletions.
33 changes: 33 additions & 0 deletions demo/src/app/components/modal/demos/options/modal-options.html
Expand Up @@ -13,8 +13,41 @@ <h4 class="modal-title">Modal title</h4>
</div>
</ng-template>

<ng-template #longContent let-modal>
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
<p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p>
<p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" (click)="modal.close('Close click')">Close</button>
</div>
</ng-template>

<button class="btn btn-outline-primary mb-2 mr-2" (click)="openWindowCustomClass(content)">Modal with window custom class</button>
<button class="btn btn-outline-primary mb-2 mr-2" (click)="openBackDropCustomClass(content)">Modal with backdrop custom class</button>
<button class="btn btn-outline-primary mb-2 mr-2" (click)="openSm(content)">Small modal</button>
<button class="btn btn-outline-primary mb-2 mr-2" (click)="openLg(content)">Large modal</button>
<button class="btn btn-outline-primary mb-2 mr-2" (click)="openVerticallyCentered(content)">Modal vertically centered</button>
<button class="btn btn-outline-primary mb-2 mr-2" (click)="openScrollableContent(longContent)">Modal scrollable content</button>
4 changes: 4 additions & 0 deletions demo/src/app/components/modal/demos/options/modal-options.ts
Expand Up @@ -42,4 +42,8 @@ export class NgbdModalOptions {
openVerticallyCentered(content) {
this.modalService.open(content, { centered: true });
}

openScrollableContent(longContent) {
this.modalService.open(longContent, { scrollable: true });
}
}
7 changes: 7 additions & 0 deletions src/modal/modal-config.ts
Expand Up @@ -60,6 +60,13 @@ export interface NgbModalOptions {
*/
keyboard?: boolean;

/**
* Scrollable modal content (false by default).
*
* @since 5.0.0
*/
scrollable?: boolean;

/**
* Size of a new modal window.
*/
Expand Down
3 changes: 2 additions & 1 deletion src/modal/modal-stack.ts
Expand Up @@ -25,7 +25,8 @@ export class NgbModalStack {
private _ariaHiddenValues: Map<Element, string> = new Map();
private _backdropAttributes = ['backdropClass'];
private _modalRefs: NgbModalRef[] = [];
private _windowAttributes = ['ariaLabelledBy', 'backdrop', 'centered', 'keyboard', 'size', 'windowClass'];
private _windowAttributes =
['ariaLabelledBy', 'backdrop', 'centered', 'keyboard', 'scrollable', 'size', 'windowClass'];
private _windowCmpts: ComponentRef<NgbModalWindow>[] = [];

constructor(
Expand Down
4 changes: 3 additions & 1 deletion src/modal/modal-window.ts
Expand Up @@ -26,7 +26,8 @@ import {ModalDismissReasons} from './modal-dismiss-reasons';
'[attr.aria-labelledby]': 'ariaLabelledBy',
},
template: `
<div [class]="'modal-dialog' + (size ? ' modal-' + size : '') + (centered ? ' modal-dialog-centered' : '')" role="document">
<div [class]="'modal-dialog' + (size ? ' modal-' + size : '') + (centered ? ' modal-dialog-centered' : '') +
(scrollable ? ' modal-dialog-scrollable' : '')" role="document">
<div class="modal-content"><ng-content></ng-content></div>
</div>
`
Expand All @@ -39,6 +40,7 @@ export class NgbModalWindow implements OnInit,
@Input() backdrop: boolean | string = true;
@Input() centered: string;
@Input() keyboard = true;
@Input() scrollable: string;
@Input() size: string;
@Input() windowClass: string;

Expand Down
14 changes: 14 additions & 0 deletions src/modal/modal.spec.ts
Expand Up @@ -803,6 +803,20 @@ describe('ngb-modal', () => {
});
});

describe('scrollable content', () => {

it('should render scrollable content modals', () => {
const modalInstance = fixture.componentInstance.open('foo', {scrollable: true});
fixture.detectChanges();
expect(fixture.nativeElement).toHaveModal('foo');
expect(document.querySelector('.modal-dialog')).toHaveCssClass('modal-dialog-scrollable');

modalInstance.close();
fixture.detectChanges();
expect(fixture.nativeElement).not.toHaveModal();
});
});

describe('accessibility', () => {

it('should support aria-labelledby', () => {
Expand Down

0 comments on commit 74fb795

Please sign in to comment.