UNPKG

@developerwellness/angular-typed-forms

Version:
288 lines (284 loc) 10.2 kB
import { InjectionToken } from '@angular/core'; import { FormArray, FormControl, FormGroup } from '@angular/forms'; function createTypedFormArray(controls, validatorOrOpts, asyncValidator) { return new TypedFormArray(controls, validatorOrOpts, asyncValidator); } class TypedFormArrayIterator { constructor(_formArray) { this._formArray = _formArray; this._index = 0; } next() { if (this._index < this._formArray.length) { const control = this._formArray.controls[this._index]; this._index++; return { value: control, done: false, }; } return { value: null, done: true, }; } } class TypedFormArray extends FormArray { constructor(controls, validatorOrOpts, asyncValidator) { super(controls, validatorOrOpts, asyncValidator); } add(value) { super.push(createTypedControls(value)); } [Symbol.iterator]() { return new TypedFormArrayIterator(this); } } function createTypedFormControl(formState, validatorOrOpts, asyncValidator) { return new TypedFormControl(formState, validatorOrOpts, asyncValidator); } class TypedFormControl extends FormControl { constructor(formState, validatorOrOpts, asyncValidator) { super(formState, validatorOrOpts, asyncValidator); } setValue(value, options) { super.setValue(value, options); } patchValue(value, options) { super.patchValue(value, options); } reset(formState, options) { super.reset(formState, options); } } function createTypedFormGroup(controls, validatorOrOpts, asyncValidator) { return new TypedFormGroup(controls, validatorOrOpts, asyncValidator); } class TypedFormGroup extends FormGroup { constructor(controls, validatorOrOpts, asyncValidator) { super(controls, validatorOrOpts, asyncValidator); } setReadonly(_value) { } getValue() { return this.value; } } function _hasValueChanged(valueA, valueB) { const result = !deepEquals(valueA.value, valueB); return result; } function _isArray(value) { return Array.isArray(value); } function _isObject(value) { return !!(typeof value === 'object' && value); } function _shouldBeProcessedFactory(options) { return (value) => !options.ignoreFields.includes(value); } function _containsErrors(value) { if (!(value === null || value === void 0 ? void 0 : value.errors)) return false; return true; } function createTypedFormGroupControls(value, options) { if (!value) return null; return Object.keys(value) .map((key) => [key, createTypedControls(value[key], options, key)]) .reduce((formGroupControls, [key, formControl]) => (Object.assign(Object.assign({}, formGroupControls), { [key]: formControl })), {}); } function _isTypedFormModel(formValue) { return (_isObject(formValue) && 'value' in formValue && ('validatorOrOpts' in formValue || 'asyncValidator' in formValue)); } function createTypedControls(formValue, options = { ignoreFields: [] }, key) { const shouldBeProcessed = _shouldBeProcessedFactory(options); if (_isArray(formValue) && shouldBeProcessed(key)) { return createTypedFormArray(formValue.map((item) => createTypedControls(item, options, key))); } else if (_isObject(formValue) && !_isTypedFormModel(formValue) && shouldBeProcessed(key)) { return createTypedFormGroup(createTypedFormGroupControls(formValue, options)); } else { return _isTypedFormModel(formValue) ? createTypedFormControl(formValue.value, formValue.validatorOrOpts, formValue.asyncValidator) : createTypedFormControl(formValue); } } function removeFormArrayControls(formArray, formValue) { forEach(new Array(formArray.length - formValue.length), () => { formArray.removeAt(0, { emitEvent: false }); }); } function updateTypedFormArray(formArray, formValue, options = { ignoreFields: [] }) { if (formArray.length > formValue.length) { removeFormArrayControls(formArray, formValue); forEach(formArray.controls, (item, index) => { updateTypedFormControls(item, formValue[index], options); }); } else { forEach(formValue, (item, index) => { if (formArray.controls[index]) { updateTypedFormControls(formArray.controls[index], item, options); } else { //Should be fixed with https://github.com/angular/angular/issues/20439#issuecomment-763976919 formArray.push(createTypedControls(item, options), { emitEvent: false }); } }); } } function updateTypedFormGroup(formGroup, formValue, options = { ignoreFields: [] }) { if (!formValue) { Object.keys(formGroup.value) .filter((key) => formGroup && formGroup.contains && formGroup.contains(key)) .map((key) => formGroup.get(key)) .forEach((itemControl) => { itemControl.patchValue(null, { emitEvent: false }); }); } else { Object.keys(formValue) .filter((key) => formGroup && formGroup.contains && formGroup.contains(key)) .map((key) => [formValue[key], formGroup.get(key), key]) .forEach(([item, itemControl, key]) => updateTypedFormControls(itemControl, item, options, key)); Object.keys(formValue) .filter((key) => formGroup && formGroup.contains && !formGroup.contains(key)) .map((key) => [key, formValue[key]]) .forEach(([key, item]) => formGroup.addControl(key, createTypedControls(item, options, key), { emitEvent: false, })); } } function updateTypedFormControl(formControl, formValue) { if (_containsErrors(formValue)) { const { errors } = formValue; formControl.setErrors(errors); } else { formControl.patchValue(formValue, { emitEvent: false }); formControl.setErrors(null); } } function updateTypedFormControls(formControl, formValue, options = { ignoreFields: [] }, key) { const _shouldBeIgnored = _shouldBeProcessedFactory(options); if (_isArray(formValue || formControl.value) && _shouldBeIgnored(key) && _hasValueChanged(formControl, formValue)) { updateTypedFormArray(formControl, formValue, options); } else if (_isObject(formControl.value || formControl.value) && _shouldBeIgnored(key) && _hasValueChanged(formControl, formValue) && (formControl === null || formControl === void 0 ? void 0 : formControl.controls)) { updateTypedFormGroup(formControl, formValue, options); } else if (_hasValueChanged(formControl, formValue)) { updateTypedFormControl(formControl, formValue); } } const FORM_GROUP_PROP = 'formGroup'; const VALUE_PROP = 'value'; function typedFormBuilderFactory(defaultValue, options = { ignoreFields: [] }) { if (!defaultValue) return null; const formGroup = createTypedControls(defaultValue, options); const controlValueProxyHandler = { get: (target, prop) => { if (target[prop] === undefined) return undefined; if (prop != FORM_GROUP_PROP) { if (Array.isArray(target[prop])) { return formGroup.get(prop); } else if (_isObject(target[prop])) { return new Proxy(target[prop], controlValueProxyHandler); } return formGroup.get(prop); } return target[prop]; }, set: (target, prop, value) => { if (prop !== FORM_GROUP_PROP) { if (prop === VALUE_PROP) { updateTypedFormControls(formGroup, value, options); } else { updateTypedFormControls(formGroup.get(prop), value, options); } } else { target[prop] = value; } return true; }, }; const formBuilder = new Proxy({ value: defaultValue, }, controlValueProxyHandler); formBuilder.formGroup = formGroup; return formBuilder; } const TYPED_FORM_BUILDER = new InjectionToken('TYPED_FORM_BUILDER'); function forEach(elements, callback, returnIf) { let result = true; const length = elements.length; for (let index = 0; index < length; index++) { result = callback(elements[index], index); if (!!returnIf && returnIf(result)) { return result; } } if (returnIf) { return result; } return false; } function deepEquals(objectA, objectB) { if ((objectA === null || objectA === undefined) && (objectB === null || objectB === undefined)) return true; if (!objectA || !objectB) return false; if (typeof objectA !== 'object' && typeof objectB !== 'object') { return objectA === objectB; } if (Array.isArray(objectA) && Array.isArray(objectB)) { if (objectA.length !== objectB.length) return false; return forEach(objectA, function (elementA, index) { return deepEquals(elementA, objectB[index]); }, function (result) { return !result; }); } if (typeof objectA === 'object' && typeof objectB === 'object') { if (Object.keys(objectA).length === 0 && Object.keys(objectA).length === 0) return true; return forEach(Object.keys(objectA), function (objectAKey) { if (typeof objectB[objectAKey] !== undefined) { return deepEquals(objectA[objectAKey], objectB[objectAKey]); } return false; }, function (result) { return !result; }); } return false; } /** * Generated bundle index. Do not edit. */ export { TYPED_FORM_BUILDER, typedFormBuilderFactory }; //# sourceMappingURL=developerwellness-angular-typed-forms.mjs.map