goteti-forms
v6.0.1
Published
Author: Narasimha Goteti
Downloads
484
Maintainers
Readme
Goteti Forms
Author: Narasimha Goteti
"GotetiForms" library is for the Angular (2+) project development.
Note: goteti-forms@6.0.0 is re-written and removed the previous versions deprecated functionalities.
Supported Functionalities are
import {
GotetiFormsModule, GtLoadElementDirectives,
GtElementRefDirective,GtLoopElementsComponent,
GtDefaultTemplatesComponent, GtDatalistComponent,
AtbrDirective, DebounceInputDirective, FilterPipe, , HighlightSearch, IpolatePipe, ListenerDirective, PermissionDirective, PermissionDirectiveDisable, SetFocusDirective,
} from 'goteti-forms';
Dox / Discussions / Issue tracker:
https://github.com/gsnr-narasimha-edu/goteti-forms-discussions/issues
Note: "goteti-forms" is Angular2+ based library , "goteti-js-forms" is vanilla JS based Form Builder based on JSON config.
Sandbox Implementation :
https://stackblitz.com/edit/stackblitz-starters-gotetiforms?file=src%2Fapp%2Fcomponents%2Fhome%2Fhome.component.html
A1) Integration Steps:
Documentation for goteti-js-forms (https://www.npmjs.com/package/goteti-js-forms)
JSON Biulder https://gotetinetwork.github.io/gtwiki
Install package in the root folder using the command,
npm i goteti-forms
npm i goteti-js-forms
Sample Code for Implementation :
app.module.ts
import { GotetiFormsModule, GtElementsService } from 'goteti-forms';
import { RatingComponent } from "./components/RatingComponent";
import { MasterTemplatesComponent } from ".components/MasterTemplatesComponent";
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
GotetiFormsModule // <--- Add the Module ,
RatingComponent // <-- Custom Input Component
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
constructor (private GES: GtElementsService){
GES.addComponent('rating', RatingComponent);
}
}
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<master-templates></master-templates>
<app-register-form></app-register-form>
`,
style: ``,
})
export class AppComponent {}
./components/register-form/register.blueprint.ts
import { GtsInputBP, GtsListBP, GtsObjectBP } from 'goteti-js-forms';
export const getRegisterBluePrint = ():
| GtsInputBP
| GtsObjectBP
| GtsListBP => {
return {
name: 'register',
isObject: true,
type: 'template',
template: 'Group', // gtEref="Group" from master-templates
fields: [
{
name: 'firstname',
label: 'First Name',
type: 'template',
template: 'Input', // gtEref="Input" from master-templates
skip: false, // Skips the rendering on page.
hide: false // disables and hides the element on page
disable: false // disables the element
validations: [
{
key: 'required',
},
],
},
{
name: 'username',
label: 'User Name',
type: 'template',
template: 'Input',
validations: [
{
key: 'required',
},
{
key: 'nospace',
},
],
},
{
name: 'contacts',
lable: 'Contacts',
isArray: true,
type: 'template',
template: 'List', // gtEref="List" from master-templates
init: 1,
fieldinfo: {
name: 'primary',
label: 'Primary Contact',
type: 'template',
template: 'Input',
},
},
{
name: 'rating',
type: 'component',
component: 'rating',
/* GES.addComponent('rating', RatingComponent); from AppModule.ts */
validations: [
{
key: 'minrating',
minvalue: 4,
},
],
},
{
name: 'yesno',
label: 'Do you accept it ?',
type: 'template',
template: 'yesnoRef',
list: ['YES', 'NO'],
validations: [],
},
{
name: 'actions',
type: 'template',
template: 'Actions',
list: [
{
key: 'submit',
label: 'Submit',
},
{
key: 'cancel',
label: 'Cancel',
},
],
},
],
};
};
./components/register-form/register.component.ts
import { Component } from '@angular/core';
import { GtsFormHub, GtsFormInput, GtsFormList, GtsFormObject, GtsFormStatusInf, } from 'goteti-js-forms';
import { getRegisterBluePrint } from './register.blueprint';
import { GotetiFormsModule } from 'goteti-forms';
import { MasterTemplatesComponent } from '../master-templates/master-templates.component';
import { CommonModule, JsonPipe, KeyValuePipe, NgFor } from '@angular/common';
@Component({
selector: 'app-register-form',
templateUrl: './register.component.html',
styleUrl: './register.component.css',
})
export class RegisterComponent {
customValidator = {
minrating: (validation: any, control: any) => {
if (validation.minvalue > control.value) {
return {
minrating: 'Minimum rating required',
};
}
return null;
},
};
formStatus: GtsFormStatusInf = {
submitted: false,
checkOnSubmit: true,
checkOnDirty: false,
checkOnTouch: false,
checkOnLoad: false,
};
formhub: GtsFormHub = new GtsFormHub(
this.customValidator,
(control: any, type: any) => {
// Callback that Detect form input changes
console.log(control?.config?.name, type, control?.value, control);
switch (type) {
case 'submit': {
this.formStatus.submitted = true;
if (this.formdata.isValid) {
}
}
}
},
this.formStatus
);
initialData: any = {
firstname: 'John',
};
otherData: any = {};
formdata: GtsFormObject | GtsFormList | GtsFormInput = this.formhub.update(
this.initialData,
getRegisterBluePrint()
);
}
./components/register-form/register.component.html
<p>Register !</p>
<gt-loop-elements
[control]="formdata"
[otherData]="otherData"
></gt-loop-elements>
<ng-template
gtEref="yesnoRef"
let-control="control"
let-config="config"
let-otherData="otherData"
>
{{ config?.label }} (Custom Template)
<div>
<button
type="button"
*ngFor="let item of config.list"
(click)="control.value = item"
[ngClass]="{ active: control.value == item }"
>
{{ item }}
</button>
<div *ngIf="control?.showErrors" style="color:red">
<small *ngFor="let err of control?.errors | keyvalue" class="gt-block">
{{ err.value }}
</small>
</div>
</div>
</ng-template>
<pre>
{{ formdata?.value | json }}
</pre>
./components/master-templates.component
You can find it at (https://stackblitz.com/edit/stackblitz-starters-gotetiforms?file=src%2Fapp%2Fcomponents%2Fmaster-templates%2Fmaster-templates.component.html)
./components/RatingComponent.ts
You can find it at (https://stackblitz.com/edit/stackblitz-starters-gotetiforms?file=src%2Fapp%2Fcomponents%2Frating%2Frating.component.ts)
Major updates information
Form Elements rendering directives / components :
1. Directive [gtEref] for storing the Template ref to the GtElementsService globally for rendering it any where in app using [gtLoadElement] attribute
3. Directive [gtLoadElement] , loads the template / component that stored in GtElementsService, GtBoxElementsService using the config in Control.
4. Component <gt-loop-elements [control]="formData"></gt-loop-elements>
for rendering all the form elements from the form control using blueprint that built by goteti-js-form builder.
5. Directive [GtFocusBlur] (onIn) (onOut) , directive that detects the focus within the element or not.
CSS class 'gtfocused' is added if focused else not.
example :
<div GtFocusBlur
[disabled]="disabled"
(onIn)="onFocusIn($event)"
(onOut)="onFocusOut($event)">
<input class="focusit" [disabled]="disabled" />
</div>
6. Use <gt-default-templates></gt-default-templates> for the library based default template refs in Root component, but be sure to use the template: 'Group' | 'List' | 'Input' in blueprints.
7. Material based input wrapper Component
<gt-mat-wrap
[floatLabel]="false"
[wrapClass]="'class'"
[appearance]="'outline'" // "standard" | "fill" | "outline"
[hasError]="false"
[hasWarning]="false"
(focusIn)="$event" // focusin, click
(focusOut)="$event" // focusout, click
>
<div class="header">
<span>{{config?.label || config?.name}}</span>
</div>
<div class="data">
<input class="focusit" [(ngModel)]="control.value" [placeholder]="config.placeholder || ''">
/*use "focusit" for auto focus on click of div */
</div>
<div class="footer">
<small> {{control.hint}}</small>
<small *ngFor="let err of control.errors | keyvalue">
{{err.value}}
</small>
</div>
</gt-mat-wrap>
8. If config has skip, hide, disable booleans configured with boolean values then control.skipped , control.hidden, control.disabled will be updated accordingly.
8.1. If control.skipped is true, form element rendering will be skipped but its 'hidden' and 'disabled' functionality will not be effected i.e no change in hidden and disabled behaviour.
8.2. If control.hidden is true, form element will be hidden and disabled is set to true so that validation checks will not be triggered.
8.3. If control.disabled is true, then validation checks will be skipped
gtLoadElement : To load the templateRef / component.
/* This method is dependent on 'goteti-js-forms' npm library */
<ng-template
gtLoadElement
[config]="{name: 'firstname',label: 'First Name', validations: [{key: 'required'}]}"
type="template"
template="defaultInputRef"
[required]="true"
[validators]="validators"
[(gtModel)]="firstName"
[hubClass]="GtsFormHub"></ng-template>
Typeahed Component :
<div class="datalist-wrap">
<input #sampleinput/>
(OR)
<input [(ngModel)]="search">
<span (click)="datalist.tall();" >
<span class="caret-down"></span>
</span>
<span (click)="test = null; sampleinput.value = '';" >
X
</span>
<gt-datalist
#datalist // datalist.tall() = toggle() + showAll()
class="dropdown"
[open]="false" // true to show options always
[search]="search" // search text to filter list (donot use [inputref])
[(value)]="test" // ngModel value
[rerun]="''" // manual check for list filteration and on selection
[rerunOnSelect]="false" // rerun check after selecting option
[disabled]="false"
multiple="true" // multiple or single value
uidprop="key" // unique key property for list of objects enabling selection.
retext="{ftext} - {key}" // default interpolation text for list of objects when value is not in list.
(viewChange)="title = $event; Console.log($event)" // selected option label
(onChange)="''" // catches event on option selection.
>
<gtoption
*ngFor="let item of list"
[uid]="item.key" // unique id used for selection option
[ftext]="item.ftext + ' ' + item.key" // Filters the list based on ftext value
[value]="item" // actual value that updates the ngModel
[valueview]="item.label" #gto> // label that shows on input selection
<div>
{{item.label}}
</div>
</gtoption>
<div class="norecords" *ngIf="datalist.empty">
No Records
</div>
</gt-datalist>
</div>
Other Usages:
<div (gtoptionUpdate)="Console.log($any($event).detail);">
<gtoption *ngFor="let item of list"
[uid]="item.id"
[ftext]="item.searchText"
[value]="item"
[valueview]="item.label" #gto
[hidden]="false"
[disabled]="false"
(gtoptionUpdate)="$any($event).detail.gtoption.selected = $any($event).detail.selected;" #gto>
{{gto.selected}}
{{ item.label }}
</gtoption>
</div>
Obsolete Notice:
1. Removed [inputref]="sampleinput" support for gt-datalist component.
2. Removed [freetext]="true" support for gt-datalist component.
B1.3) Pipe: ItpolatePipe
Example:
this.value = {
name: 'India'
}
<span> {{ value | itpolate: 'Country name is {name}' }} </span>
B1.4) Directive: AtbrDirective , depends on [random]
Example:
this.attributes = {
step: 3,
placeholder: 'This is the place holder'
};
this.random = Math.random();
<input
[atbr]="attributes"
[random]="random"
/>
B1.5) Directive: [hide] , [disable]
this.rules = {
hide: true,
disable: true
}
<input
*hide="rules.hide"
[disable]="rules.disable"
/>
[disable]="true" , Disables the element even you change the properties in developer tools i.e inspect elements.
B1.6) Directive : [listener] (ListenerDirective)
onInputChange(event){
// some functionality
}
onKeypress(event){
// some functionality
}
<input
[listener]="{input: onInputChange, keypress: onKeypress}"
[args]="['Parameter 1', 'Parameter 2']"
/>
B1.11 Directive (oninit) :
Event emits when element is initialized / destroyed
<gt-ifield
(oninit)="onElementinit()"
(ondestroy)="onElementdestroy()"
></gt-ifield>
C1. InputDebounce Decorator.
<input type="text" (input)="onInput($event)"/>
onInput(e){
this.onInputDebounce(e.target.value)
}
@InputDebounce(1500) // 1500 is the delay
onInputDebounce(...args){
console.log(args)
}
Licence
Open Source.
The author is NOT liable for any liabilities.