* [ADF-4152] Moved proc services cloud docs to subfolders * [ADF-4152] Fixed links in PS cloud docs * [ADF-4152] Added subfolders and checked links for extensions and insights docs * [ADF-4152] Moved proc services cloud docs to subfolders * [ADF-4152] Fixed links in PS cloud docs * [ADF-4152] Added subfolders and checked links for extensions and insights docs * [ADF-4152] Fixed links in Proc cloud, Insights and Extensions docs * [ADF-4152] Updated links in user guide * [ADF-4152] Fixed broken links in tutorials * [ADF-4152] Fixed remaining links in core docs * [ADF-4152] Fixed remaining links in proc services docs * [ADF-4152] Fixed remaining links in content services docs * [ADF-4152] Fixed links in breaking changes docs * [ADF-4152] Updated main README index page * [ADF-4152] Fixed glitches with preview ext component docs
11 KiB
Title, Added
Title | Added |
---|---|
Form extensibility and customization | v2.0.0 |
Form Extensibility and Customization
This page describes how you can customize ADF forms to your own specification.
Note: it is assumed you are familiar with Alfresco Process Services (powered by Activiti) form definition structure.
- How components and widgets are rendered on a
Form
- Replacing default form widgets with custom components
- Replacing custom stencils with custom components
Contents
- How components and widgets are rendered on a Form
- Replacing default form widgets with custom components
- Replacing custom stencils with custom components
- See Also
How components and widgets are rendered on a Form
All form field editors (aka widgets) on a Form
are rendered by means of FormFieldComponent
that takes an instance of a FormFieldModel
:
<form-field [field]="field"></form-field>
This component depends on FormRenderingService
service to map FormFieldModel
to UI component
based on field type or metadata information.
Component type resolvers
FormRenderingService
maps field types to corresponding instances exposing ComponentTypeResolver
interface:
export interface ComponentTypeResolver {
(field: FormFieldModel): Type<{}>;
}
Typically a ComponentTypeResolver
is a function that takes FormFieldModel
and returns corresponding component type.
It can be either a predefined component type or a dynamically evaluated based on field properties and metadata.
Static component mapping
You can (re)map fields like in the following:
let customResolver: ComponentTypeResolver = () => CustomWidgetComponent;
formRenderingService.setComponentTypeResolver('text', customResolver, true);
or simply:
formRenderingService.setComponentTypeResolver('text', () => CustomWidgetComponent, true);
Dynamic component mapping
Alternatively your resolver may return different component types based on FormFieldModel
state and condition:
let customResolver: ComponentTypeResolver = (field: FormFieldModel): Type<{}> => {
if (field) {
let params = field.params;
}
return UnknownWidgetComponent;
};
formRenderingService.setComponentTypeResolver('text', customResolver, true);
Default component mappings
Stencil Name | Field Type | Component Type |
---|---|---|
Text | text | TextWidgetComponent |
Number | integer | NumberWidgetComponent |
Multi-line text | multi-line-text | MultilineTextWidgetComponentComponent |
Checkbox | boolean | CheckboxWidgetComponent |
Dropdown | dropdown | DropdownWidgetComponent |
Date | date | DateWidgetComponent |
Amount | amount | AmountWidgetComponent |
Radio buttons | radio-buttons | RadioButtonsWidgetComponent |
Hyperlink | hyperlink | HyperlinkWidgetComponent |
Display value | readonly | DisplayValueWidgetComponent |
Display text | readonly-text | DisplayTextWidgetComponentComponent |
Typeahead | typeahead | TypeaheadWidgetComponent |
People | people | PeopleWidgetComponent |
Group of people | functional-group | FunctionalGroupWidgetComponent |
Dynamic table | dynamic-table | DynamicTableWidgetComponent |
N/A | container | ContainerWidgetComponent (layout component) |
Header | group | ContainerWidgetComponent |
Attach | upload | AttachWidgetComponent or UploadWidgetComponent (based on metadata) |
N/A | N/A | UnknownWidgetComponent |
Replacing default form widgets with custom components
This is a short walkthrough on replacing a standard Text
widget with a custom component for all APS forms
rendered within <adf-form>
component.
First let's create a simple APS form with Text
widgets:
Every custom widget must inherit WidgetComponent
class in order to function properly:
import { Component } from '@angular/core';
import { WidgetComponent } from '@alfresco/adf-core';
@Component({
selector: 'custom-editor',
template: `
<div style="color: red">Look, I'm a custom editor!</div>
`
})
export class CustomEditorComponent extends WidgetComponent {}
Now you will need to add it to the application module or any custom module that is imported into the application one:
import { NgModule } from '@angular/core';
import { CustomEditorComponent } from './custom-editor.component';
@NgModule({
declarations: [ CustomEditorComponent ],
exports: [ CustomEditorComponent ],
entryComponents: [ CustomEditorComponent ]
})
export class CustomEditorsModule {}
Every custom widget should be added into all three module collections: declarations
, exports
and entryComponents
.
If you decided to store custom widgets in a separate dedicated module (and optionally as separate redistributable library) don't forget to import it into your main application one:
@NgModule({
imports: [
// ...
CustomEditorsModule
// ...
],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
Now you can import FormRenderingService
in any of your Views and override default mapping similar to the following:
import { Component } from '@angular/core';
import { CustomEditorComponent } from './custom-editor.component';
@Component({...})
export class MyView {
constructor(formRenderingService: FormRenderingService) {
formRenderingService.setComponentTypeResolver('text', () => CustomEditorComponent, true);
}
}
At runtime it should look similar to the following:
Replacing custom stencils with custom components
This is a short walkthrough on rendering custom APS stencils by means of custom Angular components.
Creating custom stencil
First let's create a basic stencil and call it Custom Stencil 01
:
Note the internal identifier
value as it will become a field type
value when corresponding form is rendered.
Next put some simple html layout for Form
runtime template
and Form
editor template
fields:
<div style="color: blue">Custom activiti stencil</div>
Now you are ready to design a test form based on your custom stencil:
Once wired with a new task it should look like the following within APS web application:
Creating custom widget
If you load previously created task into ADF <adf-form>
component you will see something like the following:
Let's create an Angular component to render missing content:
import { Component } from '@angular/core';
import { WidgetComponent } from '@alfresco/adf-core';
@Component({
selector: 'custom-stencil-01',
template: `<div style="color: green">ADF version of custom Activiti stencil</div>`
})
export class CustomStencil01 extends WidgetComponent {}
Put it inside custom module:
import { NgModule } from '@angular/core';
import { CustomStencil01 } from './custom-stencil-01.component';
@NgModule({
declarations: [ CustomStencil01 ],
exports: [ CustomStencil01 ],
entryComponents: [ CustomStencil01 ]
})
export class CustomEditorsModule {}
And import into your Application Module
@NgModule({
imports: [
// ...
CustomEditorsModule
// ...
],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
Now you can import FormRenderingService
in any of your Views and provide new mapping:
import { Component } from '@angular/core';
import { CustomStencil01 } from './custom-stencil-01.component';
@Component({...})
export class MyView {
constructor(formRenderingService: FormRenderingService) {
formRenderingService.setComponentTypeResolver('custom_stencil_01', () => CustomStencil01, true);
}
}
At runtime you should now see your custom Angular component rendered in place of the stencils: