@datorama/akita-ng-forms-manager
Version:
The best way to manage your Angular form state in Akita
334 lines • 15 kB
JavaScript
import * as tslib_1 from "tslib";
import { Injectable, Inject, Optional } from '@angular/core';
import { FormArray, FormControl, FormGroup } from '@angular/forms';
import { coerceArray, filterNil, logAction } from '@datorama/akita';
import { merge } from 'rxjs';
import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
import { FormsQuery } from './forms-manager.query';
import { FormsStore } from './forms-manager.store';
import { FORMS_MANAGER_OPTIONS, defaultOptions } from './forms-manager-options';
import * as i0 from "@angular/core";
import * as i1 from "./forms-manager-options";
var AkitaNgFormsManager = /** @class */ (function () {
function AkitaNgFormsManager(options) {
if (options === void 0) { options = {}; }
this.valueChanges = {};
this.ngForms = {};
this._options = Object.assign({}, defaultOptions, options);
this._store = new FormsStore({});
this._query = new FormsQuery(this.store);
}
Object.defineProperty(AkitaNgFormsManager.prototype, "query", {
get: function () {
return this._query;
},
enumerable: true,
configurable: true
});
Object.defineProperty(AkitaNgFormsManager.prototype, "store", {
get: function () {
return this._store;
},
enumerable: true,
configurable: true
});
AkitaNgFormsManager.prototype.selectValid = function (formName, path) {
return this.selectControl(formName, path).pipe(map(function (control) { return control.valid; }));
};
AkitaNgFormsManager.prototype.selectDirty = function (formName, path) {
return this.selectControl(formName, path).pipe(map(function (control) { return control.dirty; }));
};
AkitaNgFormsManager.prototype.selectDisabled = function (formName, path) {
return this.selectControl(formName, path).pipe(map(function (control) { return control.disabled; }));
};
AkitaNgFormsManager.prototype.selectValue = function (formName, path) {
return this.selectControl(formName, path).pipe(map(function (control) { return control.value; }));
};
AkitaNgFormsManager.prototype.selectErrors = function (formName, path) {
return this.selectControl(formName, path).pipe(map(function (control) { return control.errors; }));
};
AkitaNgFormsManager.prototype.selectNgForm = function (formName) {
var _this = this;
return this.selectForm(formName, { filterNil: true }).pipe(map(function () { return _this.ngForms[formName]; }));
};
/**
* If no path specified it means that it's a single FormControl or FormArray
*/
AkitaNgFormsManager.prototype.selectControl = function (formName, path) {
var _this = this;
if (!path) {
return this.selectForm(formName);
}
return this.query
.select(function (state) { return state[formName]; })
.pipe(filterNil, map(function (form) { return _this.resolveControl(form, path); }), distinctUntilChanged(function (a, b) { return JSON.stringify(a) === JSON.stringify(b); }));
};
AkitaNgFormsManager.prototype.getControl = function (formName, path) {
if (!path) {
return this.getForm(formName);
}
if (this.hasForm(formName)) {
var form = this.getForm(formName);
return this.resolveControl(form, path);
}
return null;
};
AkitaNgFormsManager.prototype.selectForm = function (formName, options) {
if (options === void 0) { options = { filterNil: true }; }
return this.query.select(function (state) { return state[formName]; }).pipe(options.filterNil ? filterNil : function (s) { return s; });
};
AkitaNgFormsManager.prototype.getForm = function (formName) {
return this.query.getValue()[formName];
};
AkitaNgFormsManager.prototype.getNgForm = function (formName) {
return this.ngForms[formName];
};
AkitaNgFormsManager.prototype.hasForm = function (formName) {
return !!this.getForm(formName);
};
AkitaNgFormsManager.prototype.upsert = function (formName, form, config) {
var _this = this;
if (config === void 0) { config = {}; }
var merged = tslib_1.__assign({ debounceTime: this._options.debounceTime, emitEvent: false }, config);
/** If the form already exist, patch the form with the store value */
if (this.hasForm(formName) === true) {
form.patchValue(this.resolveStoreToForm(formName, form, merged.arrControlFactory), {
emitEvent: merged.emitEvent
});
}
else {
/** else update the store with the current form state */
this.updateStore(formName, form, true);
if (merged.persistForm) {
this.storeFormInstance(formName, form);
}
}
this.valueChanges[formName] = merge(form.valueChanges, form.statusChanges.pipe(distinctUntilChanged()))
.pipe(debounceTime(merged.debounceTime))
.subscribe(function () { return _this.updateStore(formName, form); });
return this;
};
AkitaNgFormsManager.prototype.remove = function (formName) {
var e_1, _a;
if (formName) {
this.removeFromStore(formName);
}
else {
var availableForms = Object.keys(this.query.getValue());
try {
for (var availableForms_1 = tslib_1.__values(availableForms), availableForms_1_1 = availableForms_1.next(); !availableForms_1_1.done; availableForms_1_1 = availableForms_1.next()) {
var name_1 = availableForms_1_1.value;
this.removeFromStore(name_1);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (availableForms_1_1 && !availableForms_1_1.done && (_a = availableForms_1.return)) _a.call(availableForms_1);
}
finally { if (e_1) throw e_1.error; }
}
}
this.unsubscribe(formName);
};
AkitaNgFormsManager.prototype.unsubscribe = function (formName, config) {
var _this = this;
if (config === void 0) { config = {}; }
var e_2, _a;
var _config = tslib_1.__assign({ removeNgForm: true }, { updateStore: this._options.updateStoreOnUnsubscribe }, config);
var _formName = formName;
var removeInstance = function (name) { return (_config.removeNgForm ? _this.removeFormInstance(name) : null); };
if (_formName) {
if (this.valueChanges[_formName]) {
this.valueChanges[_formName].unsubscribe();
delete this.valueChanges[_formName];
if (config.updateStore && this.ngForms[_formName]) {
this.updateStore(_formName, this.getNgForm(_formName));
}
removeInstance(_formName);
}
}
else {
try {
for (var _b = tslib_1.__values(Object.keys(this.valueChanges)), _c = _b.next(); !_c.done; _c = _b.next()) {
var name_2 = _c.value;
this.valueChanges[name_2].unsubscribe();
if (config.updateStore && this.ngForms[name_2]) {
this.updateStore(name_2, this.getNgForm(name_2));
}
removeInstance(name_2);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
this.valueChanges = {};
}
};
AkitaNgFormsManager.prototype.removeFromStore = function (formName) {
var snapshot = this.query.getValue();
var newState = Object.keys(snapshot).reduce(function (acc, currentFormName) {
if (formName !== currentFormName) {
acc[currentFormName] = snapshot[currentFormName];
}
return acc;
}, {});
logAction("Remove " + formName);
this.store._setState(function () { return newState; });
};
AkitaNgFormsManager.prototype.resolveControl = function (form, path) {
var _a = tslib_1.__read(path.split('.')), first = _a[0], rest = _a.slice(1);
if (rest.length === 0) {
return form.controls[first];
}
return this.find(form.controls[first], rest);
};
AkitaNgFormsManager.prototype.find = function (control, path) {
return path.reduce(function (current, name) {
return current.controls.hasOwnProperty(name) ? current.controls[name] : null;
}, control);
};
AkitaNgFormsManager.prototype.resolveStoreToForm = function (formName, control, arrControlFactory) {
var form = this.getForm(formName);
var value = form.value;
/** It means it a single control */
if (!form.controls) {
return value;
}
this.handleFormArray(value, control, arrControlFactory);
return value;
};
AkitaNgFormsManager.prototype.handleFormArray = function (formValue, control, arrControlFactory) {
var _this = this;
if (control instanceof FormArray) {
this.cleanArray(control);
if (!arrControlFactory) {
throw new Error('Please provide arrControlFactory');
}
formValue.forEach(function (v, i) { return control.insert(i, arrControlFactory(v)); });
}
else {
Object.keys(formValue).forEach(function (controlName) {
var value = formValue[controlName];
if (Array.isArray(value) && control.get(controlName) instanceof FormArray === true) {
if (!arrControlFactory || (arrControlFactory && controlName in arrControlFactory === false)) {
throw new Error('Please provide arrControlFactory for ' + controlName);
}
var current_1 = control.get(controlName);
var fc_1 = arrControlFactory[controlName];
_this.cleanArray(current_1);
value.forEach(function (v, i) { return current_1.insert(i, fc_1(v)); });
}
});
}
};
AkitaNgFormsManager.prototype.cleanArray = function (control) {
while (control.length !== 0) {
control.removeAt(0);
}
};
AkitaNgFormsManager.prototype.buildFormStoreState = function (formName, form) {
var e_3, _a;
var value;
if (form instanceof FormControl) {
value = this.resolveFormToStore(form);
}
if (form instanceof FormGroup || form instanceof FormArray) {
// The root form group
value = tslib_1.__assign({}, this.resolveFormToStore(form), { controls: {} });
try {
for (var _b = tslib_1.__values(Object.keys(form.controls)), _c = _b.next(); !_c.done; _c = _b.next()) {
var key = _c.value;
var control = form.controls[key];
if (control instanceof FormGroup || form instanceof FormArray) {
value.controls[key] = this.buildFormStoreState(formName, control);
}
else {
value.controls[key] = this.resolveFormToStore(control);
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_3) throw e_3.error; }
}
}
return value;
};
AkitaNgFormsManager.prototype.updateStore = function (formName, form, initial) {
if (initial === void 0) { initial = false; }
var _a;
var value = this.buildFormStoreState(formName, form);
var capitalized = formName[0].toUpperCase() + formName.slice(1);
var action = (initial ? 'Create' : 'Update') + " " + capitalized + " Form";
logAction(action);
this.store.update((_a = {},
_a[formName] = value,
_a));
};
AkitaNgFormsManager.prototype.resolveFormToStore = function (control) {
return {
value: this.cloneValue(control.value),
rawValue: control.getRawValue ? control.getRawValue() : null,
valid: control.valid,
dirty: control.dirty,
invalid: control.invalid,
disabled: control.disabled,
errors: control.errors,
touched: control.touched,
pristine: control.pristine,
pending: control.pending
};
};
AkitaNgFormsManager.prototype.cloneValue = function (value) {
return this.isObject(value) ? tslib_1.__assign({}, value) : Array.isArray(value) ? tslib_1.__spread(value) : value;
};
AkitaNgFormsManager.prototype.isObject = function (val) {
if (val == null) {
return false;
}
if (Array.isArray(val)) {
return false;
}
return typeof val === 'function' || typeof val === 'object';
};
AkitaNgFormsManager.prototype.storeFormInstance = function (formName, form) {
var _a;
var newForms = tslib_1.__assign({}, this.ngForms, (_a = {}, _a[formName] = form, _a));
this.ngForms = newForms;
};
AkitaNgFormsManager.prototype.removeFormInstance = function (formName) {
if (this.ngForms[formName]) {
delete this.ngForms[formName];
}
};
AkitaNgFormsManager.ctorParameters = function () { return [
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FORMS_MANAGER_OPTIONS,] }] }
]; };
AkitaNgFormsManager.ɵprov = i0.ɵɵdefineInjectable({ factory: function AkitaNgFormsManager_Factory() { return new AkitaNgFormsManager(i0.ɵɵinject(i1.FORMS_MANAGER_OPTIONS, 8)); }, token: AkitaNgFormsManager, providedIn: "root" });
AkitaNgFormsManager = tslib_1.__decorate([
Injectable({
providedIn: 'root'
}),
tslib_1.__param(0, Optional()), tslib_1.__param(0, Inject(FORMS_MANAGER_OPTIONS)),
tslib_1.__metadata("design:paramtypes", [Object])
], AkitaNgFormsManager);
return AkitaNgFormsManager;
}());
export { AkitaNgFormsManager };
export function setValidators(control, validator) {
control.setValidators(coerceArray(validator));
control.updateValueAndValidity();
}
export function setAsyncValidators(control, validator) {
control.setValidators(coerceArray(validator));
control.updateValueAndValidity();
}
//# sourceMappingURL=forms-manager.js.map