Skip to content

Commit

Permalink
feat: add overlayConfigFactory, a factory/helper to make it easy to…
Browse files Browse the repository at this point in the history
… open custom modals using the `open()` method
  • Loading branch information
Shlomi Assaf (shlassaf) committed Aug 30, 2016
1 parent 97adecd commit 852fd17
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 44 deletions.
1 change: 1 addition & 0 deletions src/components/angular2-modal/angular2-modal.module.ts
Expand Up @@ -25,6 +25,7 @@ import {
exports: [
CSSBackdrop,
CSSDialogContainer,
SwapComponentDirective,
OverlayDialogBoundary,
OverlayTarget,
DefaultOverlayTarget
Expand Down
1 change: 1 addition & 0 deletions src/components/angular2-modal/index.ts
Expand Up @@ -20,6 +20,7 @@ export {
export { Modal, DOMOverlayRenderer } from './providers/index';

export {
overlayConfigFactory,
OverlayContext,
OverlayContextBuilder,
ModalControllingContextBuilder
Expand Down
19 changes: 18 additions & 1 deletion src/components/angular2-modal/models/overlay-context.ts
Expand Up @@ -92,7 +92,7 @@ export class OverlayContextBuilder<T extends OverlayContext> extends FluentAssig
super(
extend<any>(DEFAULT_VALUES, defaultValues || {}),
arrayUnion<string>(DEFAULT_SETTERS, initialSetters || []),
baseType
baseType || <any>OverlayContext // https://github.com/Microsoft/TypeScript/issues/7234
);
}

Expand All @@ -111,3 +111,20 @@ export class OverlayContextBuilder<T extends OverlayContext> extends FluentAssig
export interface ModalControllingContextBuilder<T> {
open(viewContainer?: WideVCRef): Promise<DialogRef<T>>;
}

/**
* A helper to create an `OverlayConfig` on the fly.
* Since `OverlayConfig` requires context it means a builder is needed, this process had some boilerplate.
* When a quick, on the fly overlay config is needed use this helper to avoid that boilerplate.
*
* A builder is used as an API to allow setting the context and providing some operations around the modal.
* When a developers knows the context before hand we can skip this step, this is what this factory is for.
*
* @param context The context for the modal
* @param baseContextType Optional. The type/class of the context. This is the class used to init a new instance of the context
* @param baseConfig A base configuration that the result will extend
* @returns {OverlayConfig}
*/
export function overlayConfigFactory<T>(context: T, baseContextType?: any, baseConfig?: OverlayConfig): OverlayConfig {
return new OverlayContextBuilder<T & OverlayContext>(<any>context, undefined, baseContextType).toOverlayConfig(baseConfig);
}
1 change: 1 addition & 0 deletions src/components/angular2-modal/overlay/index.ts
@@ -1,3 +1,4 @@
export { OverlayTarget, OverlayDialogBoundary, DefaultOverlayTarget } from './overlay.directives'
export { ModalOverlay } from './overlay.component';
export { Overlay } from './overlay.service';

1 change: 0 additions & 1 deletion src/components/angular2-modal/plugins/bootstrap/modal.ts
Expand Up @@ -3,7 +3,6 @@ import 'rxjs/add/operator/combineLatest';
import {
Injectable,
ResolvedReflectiveProvider as RRP,
ReflectiveInjector,
Renderer
} from '@angular/core';

Expand Down
30 changes: 3 additions & 27 deletions src/components/angular2-modal/plugins/vex/dialog-form-modal.ts
@@ -1,17 +1,12 @@
import {
Component,
ComponentFactoryResolver,
ViewContainerRef,
ViewChild,
ViewEncapsulation,
AfterViewInit,
Input,
Output,
EventEmitter
} from '@angular/core';

import {
createComponent,
DialogRef,
ModalComponent
} from '../../../../components/angular2-modal';
Expand Down Expand Up @@ -77,37 +72,18 @@ export class VEXDialogButtons {
selector: 'modal-dialog',
encapsulation: ViewEncapsulation.None,
template: `<form class="vex-dialog-form">
<div style="display: none" #modalDialog></div>
<template [swapCmp]="context.content"></template>
<vex-dialog-buttons [buttons]="context.buttons"
(onButtonClick)="onButtonClick($event)"></vex-dialog-buttons>
</form>`
})
export class DialogFormModal implements AfterViewInit, ModalComponent<DialogPreset> {
export class DialogFormModal implements ModalComponent<DialogPreset> {
private context: DialogPreset;
@ViewChild('modalDialog', {read: ViewContainerRef}) private _viewContainer: ViewContainerRef;

constructor(public dialog: DialogRef<DialogPreset>,
private _cr: ComponentFactoryResolver) {
constructor(public dialog: DialogRef<DialogPreset>) {
this.context = dialog.context;
}

ngAfterViewInit() {
/* TODO:
In RC5 dynamic component creation is no longer async.
Somewhere down the pipe of the created component a value change happens that fires
a CD exception. setTimeout is a workaround that mimics the async behavior.
Find out the error and remove setTimeout.
*/
setTimeout( () => {
createComponent(
this._cr,
this.context.content,
this._viewContainer,
[]
);
});
}

onButtonClick($event: VEXButtonClickEvent) {
$event.btn.onClick(this, $event.$event);
}
Expand Down
@@ -1,9 +1,10 @@
import { Component, TemplateRef, ViewChild } from '@angular/core';

import { Modal, BSModalContextBuilder } from '../../../../components/angular2-modal/plugins/bootstrap';
import { overlayConfigFactory } from "../../../../components/angular2-modal";
import { Modal, BSModalContext } from '../../../../components/angular2-modal/plugins/bootstrap';

import { ModalCommandDescriptor } from '../../demo-head/index';
import { CustomModalContext, CustomModal } from './custom-modal-sample';
import { CustomModal } from './custom-modal-sample';
import * as presets from '../presets';


Expand Down Expand Up @@ -41,24 +42,18 @@ export class BootstrapDemoPage {
{
text: 'String content',
factory: () => this.modal
.open('Hello modal!', new BSModalContextBuilder().isBlocking(false).toOverlayConfig())
.open('Hello modal!', overlayConfigFactory({ isBlocking: false }, BSModalContext))
},
{
text: 'TemplateRef content',
factory: () => this.modal
.open(this.templateRef, new BSModalContextBuilder({ abd: 123 } as any).isBlocking(false).toOverlayConfig())
.open(this.templateRef, overlayConfigFactory({ isBlocking: false }, BSModalContext))
},
{
text: 'Custom Modal content',
factory: () => {
const builder = new BSModalContextBuilder<CustomModalContext>(
{ num1: 2, num2: 3 } as any,
undefined,
CustomModalContext
);


return this.modal.open(CustomModal, builder.toOverlayConfig());
return this.modal.open(CustomModal, overlayConfigFactory({ num1: 2, num2: 3 }, BSModalContext));
// we set the baseContextType to BSModalContext so the defaults for bootstrap will apply
}

}
Expand Down
7 changes: 4 additions & 3 deletions src/demo/app/vex-demo/vex-demo.ts
@@ -1,12 +1,13 @@
import { Component, ViewEncapsulation, ViewChild, TemplateRef } from '@angular/core';

import { overlayConfigFactory } from "../../../components/angular2-modal";
import {
VEXBuiltInThemes,
Modal,
DialogPreset,
DialogFormModal,
DialogPresetBuilder,
VEXModalContextBuilder,
VEXModalContext,
VexModalModule
} from '../../../components/angular2-modal/plugins/vex';

Expand Down Expand Up @@ -65,12 +66,12 @@ export class VexDemo {
{
text: 'String content',
factory: () => this.modal
.open('Hello modal!', new VEXModalContextBuilder().isBlocking(false).toOverlayConfig())
.open('Hello modal!', overlayConfigFactory({ isBlocking: false }, VEXModalContext))
},
{
text: 'TemplateRef content',
factory: () => this.modal
.open(this.templateRef, new VEXModalContextBuilder().isBlocking(false).toOverlayConfig())
.open(this.templateRef, overlayConfigFactory({ isBlocking: false }, VEXModalContext))
},
{
text: 'Custom Modal example',
Expand Down

0 comments on commit 852fd17

Please sign in to comment.