Skip to content

Commit

Permalink
feat(modal): allow interactions with components passed as content
Browse files Browse the repository at this point in the history
Closes #861

Closes #903
  • Loading branch information
pkozlowski-opensource committed Oct 21, 2016
1 parent a92c0e7 commit cc4ffb0
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 10 deletions.
13 changes: 8 additions & 5 deletions demo/src/app/components/modal/demos/component/modal-component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component} from '@angular/core';
import {Component, Input} from '@angular/core';

import {NgbModal, ModalDismissReasons, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';
import {NgbModal, NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';

@Component({
selector: 'ngbd-modal-content',
Expand All @@ -9,17 +9,19 @@ import {NgbModal, ModalDismissReasons, NgbActiveModal} from '@ng-bootstrap/ng-bo
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">Modal title</h4>
<h4 class="modal-title">Hi there!</h4>
</div>
<div class="modal-body">
<p>One fine body&hellip;</p>
<p>Hello, {{name}}!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="activeModal.close('Close click')">Close</button>
</div>
`
})
export class NgbdModalContent {
@Input() name;

constructor(public activeModal: NgbActiveModal) {}
}

Expand All @@ -31,6 +33,7 @@ export class NgbdModalComponent {
constructor(private modalService: NgbModal) {}

open() {
this.modalService.open(NgbdModalContent);
const modalRef = this.modalService.open(NgbdModalContent);
modalRef.componentInstance.name = 'World';
}
}
2 changes: 1 addition & 1 deletion src/modal/modal-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class NgbModalContainer {
windowCmptRef = this._viewContainerRef.createComponent(
this._windowFactory, this._viewContainerRef.length, this._injector, contentRef.nodes);

ngbModalRef = new NgbModalRef(this._viewContainerRef, windowCmptRef, backdropCmptRef, contentRef.viewRef);
ngbModalRef = new NgbModalRef(this._viewContainerRef, windowCmptRef, contentRef, backdropCmptRef);

activeModal.close = (result: any) => { ngbModalRef.close(result); };
activeModal.dismiss = (reason: any) => { ngbModalRef.dismiss(reason); };
Expand Down
20 changes: 16 additions & 4 deletions src/modal/modal-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {Injectable, ComponentRef, ViewRef, ViewContainerRef} from '@angular/core
import {NgbModalBackdrop} from './modal-backdrop';
import {NgbModalWindow} from './modal-window';

import {ContentRef} from '../util/popup';

/**
* A reference to an active (currently opened) modal. Instances of this class
* can be injected into components passed as modal content.
Expand All @@ -28,14 +30,24 @@ export class NgbModalRef {
private _resolve: (result?: any) => void;
private _reject: (reason?: any) => void;

/**
* The instance of component used as modal's content.
* Undefined when a TemplateRef is used as modal's content.
*/
get componentInstance(): any {
if (this._contentRef.componentRef) {
return this._contentRef.componentRef.instance;
}
}

/**
* A promise that is resolved when a modal is closed and rejected when a modal is dismissed.
*/
result: Promise<any>;

constructor(
private _viewContainerRef: ViewContainerRef, private _windowCmptRef: ComponentRef<NgbModalWindow>,
private _backdropCmptRef?: ComponentRef<NgbModalBackdrop>, private _contentViewRef?: ViewRef) {
private _contentRef: ContentRef, private _backdropCmptRef?: ComponentRef<NgbModalBackdrop>) {
_windowCmptRef.instance.dismissEvent.subscribe((reason: any) => { this.dismiss(reason); });

this.result = new Promise((resolve, reject) => {
Expand Down Expand Up @@ -70,12 +82,12 @@ export class NgbModalRef {
if (this._backdropCmptRef) {
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._backdropCmptRef.hostView));
}
if (this._contentViewRef) {
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentViewRef));
if (this._contentRef && this._contentRef.viewRef) {
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentRef.viewRef));
}

this._windowCmptRef = null;
this._backdropCmptRef = null;
this._contentViewRef = null;
this._contentRef = null;
}
}
7 changes: 7 additions & 0 deletions src/modal/modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ describe('ngb-modal', () => {
expect(fixture.nativeElement).not.toHaveModal();
});

it('should expose component used as modal content', () => {
const modalInstance = fixture.componentInstance.openCmpt(WithActiveModalCmpt);
fixture.detectChanges();
expect(fixture.nativeElement).toHaveModal('Close');
expect(modalInstance.componentInstance instanceof WithActiveModalCmpt).toBeTruthy();
});

it('should open and close modal from inside', () => {
fixture.componentInstance.openTplClose();
fixture.detectChanges();
Expand Down

0 comments on commit cc4ffb0

Please sign in to comment.