Created
March 24, 2022 23:37
-
-
Save JeanPaulll/c5edd4d67654c6d6d206a0e58bae00e1 to your computer and use it in GitHub Desktop.
Criar Forms Arrays Dinâmicamente
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | |
import {FormArray, FormBuilder, FormGroup} from '@angular/forms'; | |
import {environment} from '../../../../environments/environment'; | |
import {MessageBox} from '../../models/util/message-box'; | |
import {UtilForm} from '../../models/util/util-form'; | |
import {FormatForm} from './format-form'; | |
const noop = () => { | |
}; | |
declare var toastr: any; | |
/** | |
* @author Jean Paul - <jeanpaulwebb@gmail.com> | |
* @class FormArrayBaseComponent | |
* @description Criar Forms Arrays Dinâmicamente | |
* @date 16/06/2021 | |
*/ | |
@Component({ | |
selector: 'form-array-base', | |
template: ' ' | |
}) | |
export class FormArrayBaseComponent implements OnInit { | |
@Output('form') form$: EventEmitter<FormArray> = new EventEmitter<FormArray>(); | |
@Output('events') events$: EventEmitter<FormArrayEvent> = new EventEmitter<FormArrayEvent>(); | |
public onFill: EventEmitter<any> = new EventEmitter(); | |
public dev = (environment.ENV == 'dev'); | |
public utilForm = UtilForm; | |
public formReady = false; | |
@Input() title = ''; | |
public loadForm = false; | |
protected onAdd: Function = noop; | |
protected afterAdd: Function = noop; | |
protected onRemove: Function = noop; | |
protected afterRemove: Function = noop; | |
protected onEdit: Function = noop; | |
protected afterEdit: Function = noop; | |
protected indexEdit: number; | |
private __messageBox = new MessageBox(); | |
private _ready = {form: false, formInner: false, data: false}; | |
private preserveInstance = false; | |
constructor(formatForm?: FormatForm<any>) { | |
if (formatForm) { | |
this.formatForm = formatForm; | |
} else { | |
this.formInner = this.getForm(); | |
} | |
} | |
private _formatForm: FormatForm<any>; | |
get formatForm(): FormatForm<any> { | |
return this._formatForm; | |
} | |
set formatForm(value: FormatForm<any>) { | |
this._formatForm = value; | |
this.formInner = this.getForm(); | |
} | |
_showForm = false; | |
get showForm() { | |
return this._showForm; | |
} | |
set showForm(show: boolean) { | |
this._showForm = show; | |
if (show) { | |
setTimeout(() => this.loadForm = true); | |
} else { | |
this.resetForm(); | |
this.loadForm = false; | |
if (this.visualizeRoot != undefined) { | |
this.visualize = this.visualizeRoot; | |
} | |
} | |
this.events$.emit({type: 'showForm', data: show}); | |
} | |
protected _formInner: FormGroup; | |
get formInner() { | |
return this._formInner; | |
} | |
set formInner(form: FormGroup) { | |
if (!(form instanceof FormGroup)) { | |
return; | |
} | |
this._formInner = form; | |
this.formInnerChanges(); | |
this._ready.formInner = true; | |
} | |
protected _form: FormArray = new FormBuilder().array([]); | |
get form() { | |
return this._form; | |
} | |
@Input('formArray') | |
set form(form: FormArray) { | |
if (form instanceof FormArray) { | |
this._form = form; | |
this._ready.form = true; | |
if (!this._ready.data) { | |
this.data = this.data; | |
} | |
} | |
} | |
public get value() { | |
return this.form.value; | |
} | |
protected _data: any[] | any = []; | |
get data() { | |
return this._data; | |
} | |
@Input() | |
set data(data: any) { | |
this._data = data || []; | |
if (!this.form) { | |
return; | |
} | |
this.fill(data); | |
this._ready.data = true; | |
} | |
protected _dataInner: any[] | any = []; | |
get dataInner() { | |
return this._dataInner; | |
} | |
@Input() | |
set dataInner(dataInner: any) { | |
this._dataInner = this.normalizeDataForm(dataInner); | |
if (!this.formInner) { | |
return; | |
} | |
this.formInner.patchValue(this._dataInner); | |
} | |
protected _visualizeRoot: boolean; | |
get visualizeRoot(): boolean { | |
return this._visualizeRoot; | |
} | |
@Input('visualize') | |
set visualizeRoot(visualize: boolean) { | |
this._visualizeRoot = visualize; | |
this.visualize = visualize; | |
} | |
protected _visualize = false; | |
get visualize() { | |
return this._visualize; | |
} | |
set visualize(visualize: boolean) { | |
this._visualize = visualize; | |
// if(this.visualizeRoot != undefined) { | |
// | |
// } | |
this.checkVisualize(); | |
// if (!this.formInner) return; | |
// if (visualize === true) { | |
// UtilForm.disableAll(this.form); | |
// UtilForm.disableAll(this.formInner); | |
// } else { | |
// this.form.enable(); | |
// this.formInner.enable(); | |
// } | |
} | |
protected _bloqueado = false; | |
get bloqueado() { | |
return this._bloqueado; | |
} | |
@Input() | |
set bloqueado(bloqueado: boolean) { | |
this._bloqueado = bloqueado; | |
} | |
private _itemEdit: any; | |
get itemEdit(): any { | |
return this._itemEdit; | |
} | |
set itemEdit(item: any) { | |
this._itemEdit = item; | |
if (!item) { | |
this.indexEdit = undefined; | |
} | |
} | |
static clearFormArray(formArray: FormArray, repeat = true) { | |
if (!formArray) { | |
return; | |
} | |
while (formArray.controls.length) { | |
formArray.removeAt(0); | |
} | |
if (formArray.controls.length && repeat) { | |
this.clearFormArray(formArray, false); | |
} | |
} | |
public afterFill() { | |
}; | |
public beforeFill = (data) => data; | |
_enable() { | |
return this.visualize ? 'disable' : 'enable'; | |
} | |
cleanItemEdit() { | |
this.itemEdit = undefined; | |
} | |
setModel(modelDefault: any, noRequireds?: string[]) { | |
this._formatForm.setModel(modelDefault, noRequireds); | |
} | |
setPreserveInstance(preserveInstance: boolean) { | |
this.preserveInstance = preserveInstance; | |
} | |
errorGetForm() { | |
throw new Error(`✖ método não implementado. | |
Nos componentes com "extends FormArrayBaseComponent" é necessário | |
sobrescrever o método "getForm" no seguinte padrão: | |
class myComponent extends FormArrayBaseComponent { | |
... | |
getForm(data: any) { | |
if(!data) return; | |
return new FormGroup({ | |
id: new FormControl(data.id) | |
... | |
}) | |
}; | |
... | |
}`); | |
} | |
getForm(data?: any) { | |
const fb = new FormBuilder(); | |
if (!this.formatForm) { | |
return fb.group(data); | |
} | |
const form = this.formatForm.getForm(data); | |
if (typeof this.formInnerChanges === 'function' && this.formInner) { | |
try { | |
this.formInnerChanges(form); | |
} catch (e) { | |
console.error(e); | |
} | |
} | |
return form; | |
}; | |
fill(data?: any) { | |
if (!data) { | |
return; | |
} | |
data = this.beforeFill(data); | |
if (this.preserveInstance) { | |
this.form.patchValue(data); | |
} else { | |
FormArrayBaseComponent.clearFormArray(this.form); | |
if (typeof data != 'object') { | |
return; | |
} | |
if (!this.getForm) { | |
return; | |
} | |
for (let i = 0; i < data.length; i++) { | |
if (!this.form.controls[i] && data[i]) { | |
const form = this.getForm(data[i]); | |
(this.form as FormArray).push(form); | |
} | |
} | |
} | |
this.checkVisualize(); | |
this.onFill.emit(true); | |
this.afterFill(); | |
} | |
setFormatForm(formatForm?: FormatForm<any>) { | |
if (formatForm) { | |
this.formatForm = formatForm; | |
} | |
} | |
checkVisualize() { | |
if (!this.formInner) { | |
return; | |
} | |
if (this.visualize === true) { | |
UtilForm.disableAll(this.form); | |
UtilForm.disableAll(this.formInner); | |
} else { | |
this.form.enable(); | |
this.formInner.enable(); | |
} | |
} | |
verificaLista() { | |
if (this.formInner) { | |
const fullKeys = Object.keys(this.formInner.getRawValue()); | |
const keys = Object.keys(this.formInner.value); | |
const disableds = fullKeys.filter(k => !keys.includes(k)); | |
this.formatForm.setDisableds(disableds); | |
this.form.controls.map(ctrl => { | |
disableds.map(f => { | |
if (ctrl.get(f)) { | |
ctrl.get(f).disable(); | |
} | |
}); | |
// const value = (typeof ctrl['getRawValue'] == 'function') ? ctrl['getRawValue']() : ctrl.value; | |
// this.form.push(this.getForm(value)); | |
}); | |
} | |
// FormArrayBaseComponent.clearFormArray(this.form); | |
// this.form.controls.map(ctrl => { | |
// const value = (typeof ctrl['getRawValue'] == 'function') ? ctrl['getRawValue']() : ctrl.value; | |
// this.form.push(this.getForm(value)); | |
// }) | |
} | |
add(data: any = this.formInner.value, editarPorId: boolean = true) { | |
const pass = this.onAdd(); | |
if (pass === false) { | |
return; | |
} | |
data = this.normalizeDataForm(data || {}); | |
let control; | |
if (this.itemEdit) { | |
const itemEdit = this.itemEdit.value; | |
let index = null; | |
if (editarPorId) { | |
index = itemEdit.id ? (this.form.value as any[]).findIndex(v => v.id == itemEdit.id) : this.indexEdit; | |
} else { | |
index = this.indexEdit; | |
} | |
if (this.form.at(index)) { | |
this.form.at(index).patchValue(data); | |
control = this.form.at(index); | |
} else { | |
this.__messageBox.notifyError('Erro ao atualizar'); | |
// toastr.error("Erro ao atualizar"); | |
return; | |
} | |
this.itemEdit = undefined; | |
} else { | |
if (this.formInner.valid || pass === true) { | |
if (this.getForm) { | |
const form = this.getForm(data); | |
(this.form as FormArray).push(form); | |
this.form.markAsDirty(); | |
control = form; | |
} | |
} else { | |
this.__messageBox.notifyError('Preencha os campos obrigatórios'); | |
// toastr.error("Preencha os campos obrigatórios"); | |
if (this.dev) { | |
UtilForm.showFormErrors(this.formInner); | |
} | |
return; | |
} | |
} | |
this.resetForm(); | |
this.showForm = false; | |
// this.data = this.form.getRawValue(); | |
this.afterAdd(); | |
this.events$.emit({type: 'add'}); | |
return control; | |
} | |
// cancelar() { | |
// this.formInner.dirty | |
// ? this.messageBox.alertConfirm('Deseja realmente cancelar?', () => super.cancel()) | |
// : super.cancel(); | |
// } | |
normalizeDataForm(data: any) { | |
const dataDefault = this.formInner.getRawValue(); | |
return Object.keys(dataDefault).reduce((va, k) => { | |
if (dataDefault[k] && typeof dataDefault[k] === 'object' && va[k] == null) { | |
va[k] = Array.isArray(dataDefault[k]) ? [] : {}; | |
} | |
return va; | |
}, Object.assign({}, data)); | |
} | |
public remove(i: number, confirmed = false): void { | |
const pass = this.onRemove(); | |
if (!i && i != 0) { | |
return; | |
} | |
if (pass === false) { | |
return; | |
} | |
if (pass === true) { | |
confirmed = true; | |
} | |
const self = this; | |
if (!confirmed) { | |
this.__messageBox.alertConfirm('Deseja realmente excluir o registro?', (result) => { | |
if (result) { | |
if (result.isConfirmed) { | |
(self.form as FormArray).removeAt(+i); | |
self.resetForm(); | |
} | |
} | |
}); | |
} else { | |
(this.form as FormArray).removeAt(+i); | |
this.resetForm(); | |
} | |
this.afterRemove(); | |
this.events$.emit({type: 'remove'}); | |
} | |
public cancel(confirmCallback?: boolean | Function) { | |
const conf = (callback) => this.__messageBox.alertConfirm(UtilForm.msg.cancel, () => callback()); | |
const cc = () => { | |
this.itemEdit = undefined; | |
this.showForm = false; | |
this.resetForm(); | |
this.events$.emit({type: 'cancel'}); | |
typeof confirmCallback === 'function' ? confirmCallback() : null; | |
}; | |
confirmCallback ? conf(cc) : cc(); | |
} | |
public edit(i: number, visualize?: boolean, callback = () => { | |
}): void { | |
if (!visualize) { | |
visualize = false; | |
} | |
this.onEdit(); | |
if (!this.form.get('' + i)) { | |
return; | |
} | |
this.itemEdit = this.form.get('' + i); | |
this.indexEdit = i; | |
const itemEdit = this.itemEdit.value; | |
this.resetForm(); | |
this.showForm = true; | |
setTimeout(() => { | |
this.dataInner = itemEdit; | |
if (visualize) { | |
this.formInner.disable(); | |
this.form.disable(); | |
} | |
setTimeout(() => { | |
callback(); | |
}); | |
}); | |
this.afterEdit(itemEdit); | |
this.events$.emit({type: 'edit'}); | |
} | |
formInnerChanges(form?: any) { | |
} | |
readyForm() { | |
setTimeout(() => { | |
this.form$.emit(this.form); | |
}); | |
} | |
ready() { | |
setTimeout(() => this.formReady = true); | |
} | |
formErrors() { | |
UtilForm.showFormErrors(this.formInner); | |
} | |
ngOnInit() { | |
this.form$.emit(this.form); | |
} | |
protected resetForm() { | |
this.formInner.reset(); | |
this.dataInner = this.getForm().value; | |
if (this._bloqueado) { | |
this.visualize = false; | |
this.bloqueado = false; | |
} | |
} | |
} | |
export class FormArrayEvent { | |
type = null; // add, edit, remove, delete, cancel, showForm | |
data? = null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment