List Of Components
Component | Description |
---|---|
Textbox | Component used to render textbox |
Textarea | Component used to render textarea |
Checkbox | Component used to render checkbox |
Select | Component used to render dropdown with single select |
MultiSelect | Component used to render dropdown with multi select |
Topic Selector | Component used to render topic selector |
Timer | Component used to render time |
Keywords | Component used to render input tags |
Framework | Component used to render dropdown with framework values |
FrameworkCategorySelect | Component used to render dropdown with framework categories. |
Field Configuration Properties
Code Block | ||
---|---|---|
| ||
{ "code": string, // property to match the backend schema ("name", "description", etc...) "name": string, // name of the field ("Name", "Board", "Medium", "License", "Copyright Year", etc) "label": string, // title of the field "description": string, // to specify description about the field and to show as tooltip "placeholder": string, // placeholder text to appear within the field "required": boolean, // to specify if the field is mandatory or not (currently, not used.) "dataType": string, // to specify the datatype of the field outcome ("list", "number", "text") "inputType": string, // to map the field type and the component ("text", "textarea", "select", "nestedselect", etc) "visible": boolean, // to hide or show the field "editable": boolean, // to enable or disable the field "renderingHints": json, // to specify any additional configuration ex:({"class": "sb-g-col-lg-1 required"}) "depends": array, // array of "code" to specify that this field is dependant on other fields "range": array, // Array or array of objects of inputs to fields such as "select", "nestedselect", "multiselect" "options": array/function/map, // to specify the inputs to fields such as "select", "nestedselect", "multiselect", "framework", "frameworkCategorySelect" "output": string, // this field is specific to framework terms and it's associations. The field will decide the property for the field outcome ex:("name", "label", "identifier") "sourceCategory": string, // this field is specific to framework categories to map the category and association ex: (to map "subjectIds" with "subject" or to map "targetMediumIds" with "medium") "terms": array, // Array or array of object of inputs to fields related to framework and it's categories "validations": array // Array of objects to specity the validations of a field. Each validation object takes properties such as "type", "message", "value", "criteria" } |
Sample Configuration for name
field:
Code Block | ||
---|---|---|
| ||
{ "code": "name", "dataType": "text", "description": "Name of the content", "editable": true, "inputType": "text", "label": "Title", "name": "Name", "placeholder": "Title", "renderingHints": { "class": "sb-g-col-lg-1 required" }, "required": true, // currently not used to check if the field is mandatory. // "visible": true, "validations": [ { "type": "max", "value": "120", // maximum number of characters "message": "Input is Exceeded" }, { "type": "required", "message": "Title is required" } ] }, |
Custom invocation when a field’s value changes:
Code Block | ||
---|---|---|
| ||
FORMCONTROL.valueChanges.pipe( tap((value) => { // custom logic }) ); |
Custom invocation when a dependant field values changes:
Code Block | ||
---|---|---|
| ||
merge(..._.map([DependantFieldControl1, DependantFieldControl2], depend => depend.valueChanges)).pipe( tap((value) => { // custom logic }) ) |
Custom validation:
Let’s say we have two fields, maxTime
and warningTime
and assume that the condition here is warningTime
should not be greater than maxTime
Code Block | ||
---|---|---|
| ||
{ "code": "maxTime", "dataType": "text", "name": "MaxTimer", "default": "3600", "renderingHints": { "class": "sb-g-col-lg-1 required" }, "description": "MaxTime for the content", "inputType": "timer" } |
Code Block |
---|
{ "code": "warningTime", "dataType": "list", "name": "Warning Time", "depends": [ "maxTime" ], "inputType": "timer", "validations": [ { "type": "compare", "criteria": { "<": [ "maxTime" ] }, "message": "warning time should be less than max timer" } ] } |
We introduced a new type
of validations
called compare
:
Code Block |
---|
{ "type": "compare", "criteria": { "<": [ "maxTime" ] }, "message": "warning time should be less than max timer" } |
Here, criteria
is a map which takes any comparison operator as the key
and array of codes
as value.
Following is our custom function to compare two fields and handle errors if any. The function takes two arguments - criteria
and AbstractControl
.
Code Block | ||
---|---|---|
| ||
compareFields(criteria, control: AbstractControl): ValidationErrors | null { // your custom code to compare fields based on the criteria } |
Now the function can be passed to Angular by doing Validators.compose
as shown below:
Code Block |
---|
Validators.compose([compareFields.bind(this, criteria)]) |
Function compareFields
will now be called whenever warningTime
field is changes.
Custom Event Listener:
Angular by default provides two methods to listen to any field’s changes.
FormControl.valueChanges
FormControl.statusChanges
The above two methods will be immediately triggered when there is a change in the field.
Let’s assume we have a scenario where we need to make an async API call and make use of the API response, the above two methods will not help us as the API might have a delay.
To tackle this scenario, we will introduce a custom event emitter on the FormControl
.
The following interface extends the default Angular FormControl
and adds a RxJS Subject
event emitter.
Code Block | ||
---|---|---|
| ||
export interface CustomFormControl extends FormControl { customEventHandler$?: Subject<any>; } |
This will help us emit the event when the API returns a response
Code Block |
---|
ObservableAPI..subscribe( (APIResponse) => { FORMCONTROL.customEventHandler$.next(APIResponse); } ); } |
Any other fields that are dependant on this API response can now listen to this event emitter.
Code Block | ||
---|---|---|
| ||
merge(_.map(this.depends[DependantControl1, DependantControl2], depend => depend.customEventHandler$)).subscribe( (response) => { ... }, error => { ... } ) |
INPROGRESS
Closure function:
A closure function takes the following objects as its arguments.
Code Block |
---|
control: FormControl // form control of the framework field depends: [FormControl, FormControl], // array of formcontrols of the fields that the framework field depends on (if any) formGroup: FormGroup // instance of the entire FormGroup loading: anonymous function // to notify about the data loading status loaded: anonymous function // to notify about the data loaded status |
Sample Closure function:
Let’s say we have a field called framework
. On change of framework
field, if we have to invoke a logic, it can be achieved as shown below:
During the initialisation of the framework
field, we will pass the following function to options
property of framework
field.
Code Block | ||
---|---|---|
| ||
getFramework(control, depends: FormControl[], formGroup: FormGroup, loading, loaded) { const response = control.valueChanges.pipe( switchMap((value: any) => { return callFrameworkObservable() }) ); return response; } |
Field Config for framework
Code Block | ||
---|---|---|
| ||
{ "code": "framework", "visible": true, "editable": true, "dataType": "text", "label": "Course Type", "required": true, "name": "Framework", "inputType": "framework", "placeholder": "Select Course Type", "output": "identifier", "options": getFramework "validations": [ { "type": "required", "message": "Course Type is required" } ] } |