@yehia2amer/ngx-inline-editor
Version:
Follow me [](https://twitter.com/carlillo) to be notified about new releases.
233 lines (201 loc) • 5.95 kB
text/typescript
import {
Component,
ChangeDetectionStrategy,
OnInit,
forwardRef,
ComponentRef,
ComponentFactoryResolver,
ViewContainerRef,
ViewChild,
AfterViewInit,
AfterContentInit,
Inject,
ChangeDetectorRef,
Injector,
EventEmitter,
Output,
Input
// ReflectiveInjector,
// Injector,
} from '@angular/core';
import {
NG_VALUE_ACCESSOR,
ControlValueAccessor,
NgControl
} from '@angular/forms';
import { INLINE_EDITOR_INPUTS, InlineEditorEvents } from './common/index';
import { InputBase, InputWithControls } from './inputs/src/input-base';
export class InlineEditorComponent
implements OnInit, AfterViewInit, AfterContentInit, ControlValueAccessor {
input: InputBase;
private componentRef: ComponentRef<InputBase>;
private container: ViewContainerRef;
private initialValues: Partial<InitialValues> = {};
events = new InlineEditorEvents();
type: string;
config: any;
save: EventEmitter<any> = this.events.onSave;
edit: EventEmitter<any> = this.events.onEdit;
cancel: EventEmitter<any> = this.events.onCancel;
error: EventEmitter<any> = this.events.onError;
enter: EventEmitter<any> = this.events.onEnter;
escape: EventEmitter<any> = this.events.onEscape;
keyPress: EventEmitter<any> = this.events.onKeyPress;
focus: EventEmitter<any> = this.events.onFocus;
blur: EventEmitter<any> = this.events.onBlur;
click: EventEmitter<any> = this.events.onClick;
constructor(
protected cd: ChangeDetectorRef,
protected componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
protected inputs: Type<InputBase>[]
) {}
onSubmit(event: any) {}
onEdit(event: any) {}
onCancel(event: any) {}
get control(): NgControl {
const { control } =
this.input && this.input.control
? this.input
: this.injector.get(NgControl, null);
(window as any).c = control;
return control;
}
writeValue(value: any): void {
this.initialValues.value = value;
}
registerOnChange(fn: any): void {
this.initialValues.onChange = fn;
}
registerOnTouched(fn: any): void {
this.initialValues.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.initialValues.isDisabled = isDisabled;
}
ngOnInit(): void {}
ngAfterViewInit(): void {
this.generateComponent(this.type);
setTimeout(() => this.cd.markForCheck());
}
ngAfterContentInit(): void {}
private getComponentType(typeName: string = 'text'): Type<InputBase> | never {
const input = this.inputs.find(
({ type }) =>
Array.isArray(type) ? type.includes(typeName) : type === typeName
);
if (!input) {
throw new Error('That type does not exist or it is not implemented yet!');
}
return input;
}
private generateComponent(type: string = 'text'): void {
const componentType = this.getComponentType(type);
this.input = this.createInputInstance(componentType);
if (isInput(this.input)) {
this.registerInput(this.input);
} else {
throw new Error(
'The input must implement the ControlValueAccessor interface'
);
}
if (hasControl(this.input)) {
this.registerControls(this.input);
}
}
private createInputInstance(componentType: Type<InputBase>): InputBase {
// const refInjector = ReflectiveInjector.resolveAndCreate(
// this.inputs.map(input => ({ provide: input, useValue: input })),
// this.injector,
// );
const factory = this.componentFactoryResolver.resolveComponentFactory<
InputBase
>(componentType);
this.componentRef = this.container.createComponent(
factory,
undefined,
Injector.create(
[
{
provide: InlineEditorEvents,
useValue: this.events
},
{
provide: 'INLINE_EDITOR_CONFIG',
useValue: {
type: this.type,
...this.config
}
}
],
this.injector
)
);
// this.componentRef = this.container.createComponent(factory , 0, refInjector);
return this.componentRef.instance;
}
private registerInput(input: InputBase) {
// Bind methods
this.registerOnChange = input.registerOnChange.bind(input);
this.registerOnTouched = input.registerOnTouched.bind(input);
this.setDisabledState = input.setDisabledState.bind(input);
this.writeValue = input.writeValue.bind(input);
// Call methods
this.registerOnChange(this.initialValues.onChange);
this.registerOnTouched(this.initialValues.onTouched);
if (this.initialValues.isDisabled != null) {
this.setDisabledState(this.initialValues.isDisabled);
}
this.writeValue(this.initialValues.value);
}
private registerControls(input: InputWithControls) {
this.onSubmit = input.onSubmit.bind(input);
this.onCancel = input.onCancel.bind(input);
this.onEdit = input.onEdit.bind(input);
}
}
export interface Type<T> extends Function {
type: string;
new (...args: any[]): T;
}
interface InitialValues {
value: any;
onChange: any;
onTouched: any;
isDisabled: boolean;
}
export function isInput(input: any): input is InputBase {
return !!(
input.registerOnChange &&
input.registerOnTouched &&
input.writeValue
);
}
export function hasControl(input: any): input is InputWithControls {
return !!(input.onSubmit && input.onCancel);
}