#976 dynamically resolve form primitives

This commit is contained in:
Denys Vuika
2016-11-15 09:40:33 +00:00
committed by Mario Romano
parent 7ff6fd7150
commit 3092cfddaa
7 changed files with 116 additions and 75 deletions

View File

@@ -25,11 +25,8 @@
<div *ngSwitchCase="'dynamic-table'">
<dynamic-table-widget [content]="field"></dynamic-table-widget>
</div>
<div *ngSwitchCase="'readonly'">
<display-value-widget [field]="field.field" (fieldChanged)="checkVisibility($event)"></display-value-widget>
</div>
<div *ngSwitchDefault>
<span>UNKNOWN WIDGET TYPE: {{field.type}}</span>
<form-field [field]="field.field"></form-field>
</div>
</div>
</div>

View File

@@ -48,7 +48,7 @@ export class FormFieldComponent implements OnInit {
ngOnInit() {
if (this.field) {
let componentType = this.formRenderingService.getComponentType(this.field.type);
let componentType = this.formRenderingService.resolveComponentType(this.field);
if (componentType) {
let factory = this.componentFactoryResolver.resolveComponentFactory(componentType);
this.componentRef = this.container.createComponent(factory/*, 0, this.injector*/);

View File

@@ -15,57 +15,7 @@
<div *ngFor="let col of content.columns" class="mdl-cell mdl-cell--{{col.size}}-col">
<div class="mdl-grid" *ngIf="col.hasFields()">
<div *ngFor="let field of col.fields" class="mdl-cell mdl-cell--12-col">
<div [ngSwitch]="field.type" [hidden]="!field.isVisible">
<div *ngSwitchCase="'integer'">
<number-widget [field]="field" (fieldChanged)="fieldChanged($event);"></number-widget>
</div>
<div *ngSwitchCase="'text'">
<form-field [field]="field"></form-field>
</div>
<div *ngSwitchCase="'multi-line-text'">
<multiline-text-widget [field]="field" (fieldChanged)="fieldChanged($event);"></multiline-text-widget>
</div>
<div *ngSwitchCase="'boolean'">
<checkbox-widget [field]="field" (fieldChanged)="fieldChanged($event);"></checkbox-widget>
</div>
<div *ngSwitchCase="'dropdown'">
<dropdown-widget [field]="field" (fieldChanged)="fieldChanged($event);"></dropdown-widget>
</div>
<div *ngSwitchCase="'hyperlink'">
<hyperlink-widget [field]="field" (fieldChanged)="fieldChanged($event);"></hyperlink-widget>
</div>
<div *ngSwitchCase="'radio-buttons'">
<radio-buttons-widget [field]="field" (fieldChanged)="fieldChanged($event);"></radio-buttons-widget>
</div>
<div *ngSwitchCase="'readonly'">
<display-value-widget [field]="field" (fieldChanged)="fieldChanged($event);"></display-value-widget>
</div>
<div *ngSwitchCase="'readonly-text'">
<display-text-widget [field]="field" (fieldChanged)="fieldChanged($event);"></display-text-widget>
</div>
<div *ngSwitchCase="'upload'">
<upload-widget *ngIf="!field.params.link" [field]="field" (fieldChanged)="fieldChanged($event);"></upload-widget>
<attach-widget *ngIf="field.params.link" [field]="field" (fieldChanged)="fieldChanged($event);"></attach-widget>
</div>
<div *ngSwitchCase="'typeahead'">
<typeahead-widget [field]="field" (fieldChanged)="fieldChanged($event);"></typeahead-widget>
</div>
<div *ngSwitchCase="'functional-group'">
<functional-group-widget [field]="field" (fieldChanged)="fieldChanged($event);"></functional-group-widget>
</div>
<div *ngSwitchCase="'people'">
<people-widget [field]="field" (fieldChanged)="fieldChanged($event);"></people-widget>
</div>
<div *ngSwitchCase="'date'">
<date-widget [field]="field" (fieldChanged)="fieldChanged($event);"></date-widget>
</div>
<div *ngSwitchCase="'amount'">
<amount-widget [field]="field" (fieldChanged)="fieldChanged($event);"></amount-widget>
</div>
<div *ngSwitchDefault>
<span>UNKNOWN WIDGET TYPE: {{field.type}}</span>
</div>
</div>
<form-field [field]="field" [hidden]="!field.isVisible"></form-field>
</div>
</div>
</div>

View File

@@ -15,6 +15,7 @@
* limitations under the License.
*/
import { UnknownWidget } from './unknown/unknown.widget';
import { TabsWidget } from './tabs/tabs.widget';
import { ContainerWidget } from './container/container.widget';
@@ -50,6 +51,7 @@ export * from './tabs/tabs.widget';
export * from './container/container.widget';
// primitives
export * from './unknown/unknown.widget';
export * from './text/text.widget';
export * from './number/number.widget';
export * from './checkbox/checkbox.widget';
@@ -76,6 +78,7 @@ export * from './dynamic-table/editors/boolean/boolean.editor';
export * from './dynamic-table/editors/text/text.editor';
export const WIDGET_DIRECTIVES: any[] = [
UnknownWidget,
TabsWidget,
ContainerWidget,
TextWidget,

View File

@@ -23,11 +23,8 @@
<div *ngSwitchCase="'dynamic-table'">
<dynamic-table-widget [content]="field"></dynamic-table-widget>
</div>
<div *ngSwitchCase="'readonly'">
<display-value-widget [field]="field.field" (fieldChanged)="tabChanged($event);"></display-value-widget>
</div>
<div *ngSwitchDefault>
<span>UNKNOWN WIDGET TYPE: {{field.type}}</span>
<form-field [field]="field.field"></form-field>
</div>
</div>
</div>

View File

@@ -0,0 +1,31 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component } from '@angular/core';
import { WidgetComponent } from './../widget.component';
@Component({
selector: 'unknown-widget',
template: `
<div>
<i class="material-icons">error_outline</i>
<span style="color: red">Unknown type: {{field.type}}</span>
</div>
`
})
export class UnknownWidget extends WidgetComponent {
}

View File

@@ -17,41 +17,104 @@
import { Injectable, Type } from '@angular/core';
import { TextWidget } from './../components/widgets/text/text.widget';
import {
FormFieldModel,
UnknownWidget,
TextWidget,
MultilineTextWidget,
NumberWidget,
CheckboxWidget,
DropdownWidget,
DateWidget,
AmountWidget,
RadioButtonsWidget,
HyperlinkWidget,
DisplayValueWidget,
DisplayTextWidget,
TypeaheadWidget,
PeopleWidget,
FunctionalGroupWidget,
DynamicTableWidget,
AttachWidget,
UploadWidget
} from './../components/widgets/index';
@Injectable()
export class FormRenderingService {
private types: { [key: string]: Type<{}> } = {
'text': TextWidget
private types: { [key: string]: ComponentTypeResolver } = {
'text': DefaultTypeResolver.fromType(TextWidget),
'integer': DefaultTypeResolver.fromType(NumberWidget),
'multi-line-text': DefaultTypeResolver.fromType(MultilineTextWidget),
'boolean': DefaultTypeResolver.fromType(CheckboxWidget),
'dropdown': DefaultTypeResolver.fromType(DropdownWidget),
'date': DefaultTypeResolver.fromType(DateWidget),
'amount': DefaultTypeResolver.fromType(AmountWidget),
'radio-buttons': DefaultTypeResolver.fromType(RadioButtonsWidget),
'hyperlink': DefaultTypeResolver.fromType(HyperlinkWidget),
'readonly': DefaultTypeResolver.fromType(DisplayValueWidget),
'readonly-text': DefaultTypeResolver.fromType(DisplayTextWidget),
'typeahead': DefaultTypeResolver.fromType(TypeaheadWidget),
'people': DefaultTypeResolver.fromType(PeopleWidget),
'functional-group': DefaultTypeResolver.fromType(FunctionalGroupWidget),
'dynamic-table': DefaultTypeResolver.fromType(DynamicTableWidget)
};
getComponentType(fieldType: string): Type<{}> {
if (fieldType) {
return this.types[fieldType] || null;
}
return null;
constructor() {
this.types['upload'] = (field: FormFieldModel): Type<{}> => {
if (field) {
let params = field.params;
if (params && params.link) {
return AttachWidget;
}
return UploadWidget;
}
return null;
};
}
setComponentType(fieldType: string, componentType: Type<{}>, override: boolean = false) {
getComponentTypeResolver(fieldType: string, defaultValue: Type<{}> = UnknownWidget): ComponentTypeResolver {
if (fieldType) {
return this.types[fieldType] || DefaultTypeResolver.fromType(defaultValue);
}
return DefaultTypeResolver.fromType(defaultValue);
}
setComponentTypeResolver(fieldType: string, resolver: ComponentTypeResolver, override: boolean = false) {
if (!fieldType) {
throw new Error(`fieldType is null or not defined`);
}
if (!componentType) {
throw new Error(`componentType is null or not defined`);
if (!resolver) {
throw new Error(`resolver is null or not defined`);
}
let existing = this.types[fieldType];
if (existing && !override) {
throw new Error(`componentType is already mapped, use override option if you intend replacing existing mapping.`);
throw new Error(`already mapped, use override option if you intend replacing existing mapping.`);
}
this.types[fieldType] = componentType;
this.types[fieldType] = resolver;
}
constructor() {
this.setComponentType('xx', TextWidget);
resolveComponentType(field: FormFieldModel, defaultValue: Type<{}> = UnknownWidget): Type<{}> {
if (field) {
let resolver = this.getComponentTypeResolver(field.type, defaultValue);
return resolver(field);
}
return defaultValue;
}
}
export interface ComponentTypeResolver {
(field: FormFieldModel): Type<{}>;
}
export class DefaultTypeResolver {
static fromType(type: Type<{}>): ComponentTypeResolver {
return (field: FormFieldModel) => {
return type;
};
}
}