Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Greentube/ngx-modal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: yduartep/ngx-modal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 5 commits
  • 16 files changed
  • 2 contributors

Commits on Sep 9, 2018

  1. Adding Custom Header component implementation

    Yahima Duarte committed Sep 9, 2018
    Copy the full SHA
    bb2c482 View commit details
  2. Adding Custom Header component implementation

    Yahima Duarte committed Sep 9, 2018
    Copy the full SHA
    e67cc95 View commit details
  3. Copy the full SHA
    62445b8 View commit details
  4. Adding Custom Header component implementation

    Yahima Duarte committed Sep 9, 2018
    Copy the full SHA
    ab9942b View commit details
  5. Adding Custom Header component implementation

    Yahima Duarte committed Sep 9, 2018
    Copy the full SHA
    0b83b33 View commit details
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -96,6 +96,50 @@ Action button can be of two types:
- without return value
Has no direct effect on dialog. Can be used to trigger some arbitrary functionality (e.g. copy values to clipboard)

### Custom Header
1. Create a custom header component that implements `IModalHeaderDialog`.

```ts
import {Component} from '@angular/core';
import {IModalHeaderDialog} from 'ngx-modal-dialog';

@Component({
selector: 'app-custom-header-modal',
template: `
<h4>This component is a custom header</h4>
<p>Written By: <b>{{title}}</b></p>
`
})
export class CustomHeaderModalComponent implements IModalHeaderDialog {
title: string;

setData(data: any) {
this.title = data['title'];
}
}
```

2. Inject the `ModalDialogService` where you want to open the dialog passing the headerComponent as a new option parameter instead of the title attribute and change the value of the new parameter headerType to CUSTOM:
```ts
constructor(modalService: ModalDialogService, viewRef: ViewContainerRef) { }

openCustomHeaderModal() {
this.modalDialogService.openDialog(this.viewContainer, {
headerComponent: CustomHeaderModalComponent,
childComponent: SimpleModalComponent,
settings: {
closeButtonClass: 'close theme-icon-close',
headerType: ModalDialogHeaderType.CUSTOM
},
data: {
title: 'Yahima Duarte <layahi@gmail.com>',
text: `Lorem ipsum is placeholder text commonly used in the graphic, print,
and publishing industries for previewing layouts and visual mockups.`
}
});
}
```

## API

### ModalDialogService
@@ -122,6 +166,7 @@ Modal heading text
```ts
interface IModalDialogOptions<T> {
title: string;
headerComponent: IModalHeaderDialog;
childComponent: IModalDialog;
onClose: ModalDialogOnAction;
actionButtons: IModalDialogButton[];
@@ -136,6 +181,9 @@ This is generic interface, where `T` is arbitrary type of `data` section.
- title: `string`
Modal heading text

- headerComponent: `any`
Component type that will be rendered as a header of modal dialog. Component must implement `IModalHeaderDialog` interface.

- childComponent: `any`
Component type that will be rendered as a content of modal dialog. Component must implement `IModalDialog` interface.

@@ -212,6 +260,7 @@ interface IModalDialogSettings {
alertDuration: number;
buttonClass: string;
notifyWithAlert: boolean;
headerType: ModalDialogHeaderType;
}
```

@@ -264,6 +313,8 @@ Style of footer action buttons
- notifyWithAlert: `number`
Default: `true`
Define whether modal should alert user when action fails

- headerType: `ModalDialogHeaderType`
Default: `TITLE`
Define which kind of header would be displayed. If the value is TITLE just the title attribute will be displayed. If the value is CUSTOM and the headerComponent option was defined, the custom header component will be displayed.
## License
Licensed under MIT
2 changes: 1 addition & 1 deletion demo/package.json
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@
"karma-coverage-istanbul-reporter": "~2.0.0",
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.3.0",
"protractor": "^5.4.0",
"ts-node": "~5.0.1",
"tslint": "~5.9.1",
"typescript": "~2.7.2"
5 changes: 5 additions & 0 deletions demo/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -27,6 +27,11 @@
<button class="btn btn-success" type="button" (click)="openCustomModal()">Dialog with custom child component</button>
</div>
</div>
<div class="row mb-2">
<div class="col">
<button class="btn btn-success" type="button" (click)="openCustomHeaderModal()">Dialog with custom header component</button>
</div>
</div>
<div class="row mb-2">
<div class="col">
<button class="btn btn-danger" type="button" (click)="openMultipleModal()">Multiple modal dialogs on top of each other</button>
48 changes: 35 additions & 13 deletions demo/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Component, ViewContainerRef } from '@angular/core';
import { ModalDialogService, SimpleModalComponent } from 'ngx-modal-dialog';
import { CustomModalComponent } from './dialogs/custom-modal.component';
import { DynamicModalComponent } from './dialogs/dynamic-modal.component';
import {Component, ViewContainerRef} from '@angular/core';
import {CustomModalComponent} from './dialogs/custom-modal.component';
import {DynamicModalComponent} from './dialogs/dynamic-modal.component';
import {CustomHeaderModalComponent} from './dialogs/custom-header-modal.component';
import {ModalDialogHeaderType, ModalDialogService, SimpleModalComponent} from 'ngx-modal-dialog';

@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
constructor(private modalDialogService: ModalDialogService, private viewContainer: ViewContainerRef) {}
constructor(private modalDialogService: ModalDialogService, private viewContainer: ViewContainerRef) {
}

openSimpleModal() {
this.modalDialogService.openDialog(this.viewContainer, {
@@ -92,6 +94,22 @@ export class AppComponent {
});
}

openCustomHeaderModal() {
this.modalDialogService.openDialog(this.viewContainer, {
headerComponent: CustomHeaderModalComponent,
childComponent: SimpleModalComponent,
settings: {
closeButtonClass: 'close theme-icon-close',
headerType: ModalDialogHeaderType.CUSTOM
},
data: {
title: 'Yahima Duarte <layahi@gmail.com>',
text: `Lorem ipsum is placeholder text commonly used in the graphic, print,
and publishing industries for previewing layouts and visual mockups.`
}
});
}

openDynamicModal() {
this.modalDialogService.openDialog(this.viewContainer, {
title: 'Dynamic child component',
@@ -106,30 +124,34 @@ export class AppComponent {
this.modalDialogService.openDialog(this.viewContainer, {
title: 'Dialog 1',
childComponent: SimpleModalComponent,
settings: { closeButtonClass: 'close theme-icon-close' },
settings: {closeButtonClass: 'close theme-icon-close'},
placeOnTop: true,
data: { text: `
data: {
text: `
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.` }
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`
}
});
this.modalDialogService.openDialog(this.viewContainer, {
title: 'Dialog 2',
childComponent: SimpleModalComponent,
settings: { closeButtonClass: 'close theme-icon-close' },
settings: {closeButtonClass: 'close theme-icon-close'},
placeOnTop: true,
data: { text: `
data: {
text: `
Lorem ipsum is placeholder text commonly used in the graphic, print,
and publishing industries for previewing layouts and visual mockups.` }
and publishing industries for previewing layouts and visual mockups.`
}
});
this.modalDialogService.openDialog(this.viewContainer, {
title: 'Dialog 3',
childComponent: SimpleModalComponent,
settings: { closeButtonClass: 'close theme-icon-close' },
settings: {closeButtonClass: 'close theme-icon-close'},
placeOnTop: true,
data: { text: 'Some text content' }
data: {text: 'Some text content'}
});
}
}
20 changes: 11 additions & 9 deletions demo/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { CustomModalComponent } from './dialogs/custom-modal.component';
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import { ModalDialogModule } from 'ngx-modal-dialog';
import { DynamicModalComponent } from './dialogs/dynamic-modal.component';

import {AppComponent} from './app.component';
import {CustomModalComponent} from './dialogs/custom-modal.component';
import {DynamicModalComponent} from './dialogs/dynamic-modal.component';
import {CustomHeaderModalComponent} from './dialogs/custom-header-modal.component';

@NgModule({
declarations: [AppComponent, CustomModalComponent, DynamicModalComponent],
declarations: [AppComponent, CustomModalComponent, DynamicModalComponent, CustomHeaderModalComponent],
imports: [
BrowserModule,
ModalDialogModule.forRoot()
],
entryComponents: [CustomModalComponent, DynamicModalComponent],
entryComponents: [CustomModalComponent, DynamicModalComponent, CustomHeaderModalComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
export class AppModule {
}
17 changes: 17 additions & 0 deletions demo/src/app/dialogs/custom-header-modal.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {Component} from '@angular/core';
import {IModalHeaderDialog} from 'ngx-modal-dialog';

@Component({
selector: 'app-custom-header-modal',
template: `
<h4>This component is a custom header</h4>
<p>Written By: <b>{{title}}</b></p>
`
})
export class CustomHeaderModalComponent implements IModalHeaderDialog {
title: string;

setData(data: any) {
this.title = data['title'];
}
}
2 changes: 1 addition & 1 deletion demo/src/app/dialogs/custom-modal.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IModalDialog, IModalDialogOptions } from 'ngx-modal-dialog';
import { Component, ComponentRef } from '@angular/core';
import {IModalDialog, IModalDialogOptions} from 'ngx-modal-dialog';

@Component({
selector: 'app-custom-modal',
2 changes: 1 addition & 1 deletion demo/src/app/dialogs/dynamic-modal.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IModalDialog, IModalDialogOptions } from 'ngx-modal-dialog';
import { Component, ComponentRef } from '@angular/core';
import {IModalDialog, IModalDialogOptions} from 'ngx-modal-dialog';

@Component({
selector: 'app-dynamic-modal',
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -3,3 +3,4 @@ export * from './src/modal-dialog.service';
export * from './src/modal-dialog.component';
export * from './src/modal-dialog.interface';
export * from './src/simple-modal.component';
export * from './src/modal-dialog.header-type';
8 changes: 8 additions & 0 deletions src/modal-dialog.ad-header.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
selector: '[ad-header]',
})
export class AdHeaderDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
52 changes: 36 additions & 16 deletions src/modal-dialog.component.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import {
Component,
ComponentRef,
ComponentFactoryResolver,
ViewContainerRef,
ViewChild,
OnDestroy, OnInit,
HostListener, ElementRef
Component,
ComponentFactoryResolver,
ComponentRef,
ElementRef,
HostListener,
OnDestroy,
OnInit,
ViewChild,
ViewContainerRef
} from '@angular/core';
import {
IModalDialog,
IModalDialogOptions,
IModalDialogButton,
IModalDialogSettings, ModalDialogOnAction
IModalDialog,
IModalDialogButton,
IModalDialogOptions,
IModalDialogSettings,
IModalHeaderDialog,
ModalDialogOnAction
} from './modal-dialog.interface';
import { Observable, Subject, from } from 'rxjs';
import { from, Observable, Subject } from 'rxjs';
import { AdHeaderDirective } from './modal-dialog.ad-header.directive';
import { ModalDialogHeaderType } from './modal-dialog.header-type';

/**
* Modal dialog component
@@ -62,7 +68,10 @@ import { Observable, Subject, from } from 'rxjs';
<div [ngClass]="settings.modalDialogClass">
<div [ngClass]="[ showAlert ? settings.alertClass : '', settings.contentClass]">
<div [ngClass]="settings.headerClass">
<h4 [ngClass]="settings.headerTitleClass">{{title}}</h4>
<div [ngClass]="settings.headerTitleClass">
<ng-template ad-header></ng-template>
<h4 *ngIf="settings.headerType === 1">{{title}}</h4>
</div>
<button (click)="close()" *ngIf="!actionButtons || !actionButtons.length" type="button"
[title]="settings.closeButtonTitle"
[ngClass]="settings.closeButtonClass">
@@ -83,6 +92,7 @@ import { Observable, Subject, from } from 'rxjs';
})
export class ModalDialogComponent implements IModalDialog, OnDestroy, OnInit {
@ViewChild('modalDialogBody', { read: ViewContainerRef }) public dynamicComponentTarget: ViewContainerRef;
@ViewChild(AdHeaderDirective) adHeader: AdHeaderDirective;
@ViewChild('dialog') private dialogElement: ElementRef;
public reference: ComponentRef<IModalDialog>;

@@ -103,7 +113,8 @@ export class ModalDialogComponent implements IModalDialog, OnDestroy, OnInit {
alertClass: 'ngx-modal-shake',
alertDuration: 250,
notifyWithAlert: true,
buttonClass: 'btn btn-primary'
buttonClass: 'btn btn-primary',
headerType: ModalDialogHeaderType.TITLE
};
public actionButtons: IModalDialogButton[];
public title: string;
@@ -147,8 +158,8 @@ export class ModalDialogComponent implements IModalDialog, OnDestroy, OnInit {

// inject component
if (options.childComponent) {
let factory = this.componentFactoryResolver.resolveComponentFactory(options.childComponent);
let componentRef = this.dynamicComponentTarget.createComponent(factory) as ComponentRef<IModalDialog>;
const factory = this.componentFactoryResolver.resolveComponentFactory(options.childComponent);
const componentRef = this.dynamicComponentTarget.createComponent(factory) as ComponentRef<IModalDialog>;
this._childInstance = componentRef.instance as IModalDialog;

this._closeDialog$ = new Subject<void>();
@@ -165,6 +176,15 @@ export class ModalDialogComponent implements IModalDialog, OnDestroy, OnInit {
}
// set options
this._setOptions(options);

if (this.settings.headerType === ModalDialogHeaderType.CUSTOM && options.headerComponent) {
const factory = this.componentFactoryResolver.resolveComponentFactory(options.headerComponent);

const viewContainerRef = this.adHeader.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent(factory);
(<IModalHeaderDialog>componentRef.instance).setData(options.data);
}
}

ngOnInit() {
3 changes: 3 additions & 0 deletions src/modal-dialog.header-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum ModalDialogHeaderType {
TITLE = 1, CUSTOM = 2
}
11 changes: 9 additions & 2 deletions src/modal-dialog.interface.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { ComponentRef } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import {ComponentRef} from '@angular/core';
import {Observable, Subject} from 'rxjs';
import {ModalDialogHeaderType} from './modal-dialog.header-type';

export interface IModalDialog {
dialogInit: (reference: ComponentRef<IModalDialog>, options: Partial<IModalDialogOptions<any>>) => void;
}

export interface IModalHeaderDialog {
setData(data: any): void;
}

export interface IModalDialogOptions<T> {
title: string;
headerComponent: any;
childComponent: any;
onClose: () => Promise<any> | Observable<any> | boolean;
actionButtons: IModalDialogButton[];
@@ -42,4 +48,5 @@ export interface IModalDialogSettings {
alertDuration: number;
buttonClass: string;
notifyWithAlert: boolean;
headerType: ModalDialogHeaderType;
}
Loading