@reactables/forms 0.4.5-alpha.0 → 0.5.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,7 @@ interface AsyncFields {
22
22
  interface ValidatedFields {
23
23
  valid: boolean;
24
24
  errors: FormErrors;
25
+ childrenValid: boolean;
25
26
  }
26
27
  export interface Hub2Fields extends AsyncFields, ValidatedFields {
27
28
  }
@@ -39,4 +40,5 @@ export interface Form<T> {
39
40
  root?: FormControl<T>;
40
41
  [key: string]: FormControl<unknown>;
41
42
  }
43
+ export declare const DEFAULT_HUB2_FIELDS: Hub2Fields;
42
44
  export {};
@@ -9,6 +9,10 @@ export interface AddControl {
9
9
  config: AbstractControlConfig;
10
10
  controlRef: ControlRef;
11
11
  }
12
+ export interface PushControl {
13
+ config: AbstractControlConfig;
14
+ controlRef: ControlRef;
15
+ }
12
16
  export interface ControlAsyncValidationResponse {
13
17
  key: string;
14
18
  validatorIndex: number;
@@ -0,0 +1,4 @@
1
+ import { Action } from '@reactables/core';
2
+ import { BaseFormState } from '../../Models/Controls';
3
+ import { AddControl } from '../../Models/Payloads';
4
+ export declare const pushControl: <T>(state: BaseFormState<T>, action: Action<AddControl>) => BaseFormState<T>;
@@ -1,4 +1,3 @@
1
1
  import { Reducer } from '@reactables/core';
2
- import { Form, Hub2Fields } from '../../Models/Controls';
3
- export declare const DEFAULT_HUB2_FIELDS: Hub2Fields;
2
+ import { Form } from '../../Models/Controls';
4
3
  export declare const formChange: Reducer<Form<unknown>>;
@@ -0,0 +1,5 @@
1
+ import { Form, BaseForm } from '../../Models/Controls';
2
+ import { ControlRef } from '../../Models/ControlRef';
3
+ export declare const mergePushControl: <T>(state: Form<T>, form: BaseForm<T>, controlRef: ControlRef) => {
4
+ root?: import("../../Models/Controls").FormControl<unknown>;
5
+ };
@@ -1,3 +1,6 @@
1
- import { Form, BaseForm } from '../../Models/Controls';
1
+ import { Form, BaseForm, FormControl } from '../../Models/Controls';
2
2
  import { ControlRef } from '../../Models/ControlRef';
3
- export declare const mergeRemoveControl: <T>(state: Form<T>, form: BaseForm<T>, controlRef: ControlRef) => Form<T>;
3
+ export declare const mergeRemoveControl: <T>(state: Form<T>, form: BaseForm<T>, controlRef: ControlRef) => {
4
+ [x: string]: FormControl<unknown>;
5
+ root?: FormControl<T>;
6
+ };
@@ -1,3 +1,6 @@
1
- import { Form, BaseForm } from '../../Models/Controls';
1
+ import { Form, BaseForm, FormControl } from '../../Models/Controls';
2
2
  import { ControlRef } from '../../Models/ControlRef';
3
- export declare const mergeValueUpdated: <T>(state: Form<T>, form: BaseForm<T>, controlRef: ControlRef) => Form<T>;
3
+ export declare const mergeValueUpdated: <T>(state: Form<T>, form: BaseForm<T>, controlRef: ControlRef) => {
4
+ [x: string]: FormControl<unknown>;
5
+ root?: FormControl<T>;
6
+ };
@@ -1,5 +1,5 @@
1
1
  import { Reactable, EffectsAndSources } from '@reactables/core';
2
- import { ControlChange, AddControl, MarkTouched } from '../Models/Payloads';
2
+ import { ControlChange, AddControl, MarkTouched, PushControl } from '../Models/Payloads';
3
3
  import { ControlRef } from '../Models';
4
4
  import { FormControlConfig, FormArrayConfig, FormGroupConfig, AbstractControlConfig } from '../Models/Configs';
5
5
  import { ValidatorFn, ValidatorAsyncFn } from '../Models/Validators';
@@ -8,6 +8,7 @@ type FbControl<T> = [T, (ValidatorFn | ValidatorFn[])?, (ValidatorAsyncFn | Vali
8
8
  export type RxFormActions = {
9
9
  updateValues: <T>(payload: ControlChange<T>) => void;
10
10
  addControl: (payload: AddControl) => void;
11
+ pushControl: (payload: PushControl) => void;
11
12
  removeControl: (payload: ControlRef) => void;
12
13
  markControlAsPristine: (payload: ControlRef) => void;
13
14
  markControlAsTouched: (payload: MarkTouched) => void;
package/dist/index.js CHANGED
@@ -11,8 +11,18 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
11
11
 
12
12
  var isEqual__default = /*#__PURE__*/_interopDefaultLegacy(isEqual);
13
13
 
14
+ var DEFAULT_HUB2_FIELDS = {
15
+ asyncValidatorErrors: {},
16
+ asyncValidateInProgress: {},
17
+ pending: false,
18
+ valid: null,
19
+ childrenValid: null,
20
+ errors: null
21
+ };
22
+
14
23
  var Controls = /*#__PURE__*/Object.freeze({
15
- __proto__: null
24
+ __proto__: null,
25
+ DEFAULT_HUB2_FIELDS: DEFAULT_HUB2_FIELDS
16
26
  });
17
27
 
18
28
  var required = function (value) {
@@ -122,16 +132,9 @@ var generateKey = function (length) {
122
132
  return result;
123
133
  };
124
134
 
125
- var syncValidate = function (form) {
126
- // First check each control for its own validation
127
- var validated = Object.entries(form).reduce(function (acc, _a) {
128
- var _b;
129
- var _c;
130
- var key = _a[0], control = _a[1];
131
- var validatorErrors = ((_c = control.config.validators) === null || _c === void 0 ? void 0 : _c.reduce(function (acc, validator) { return (__assign(__assign({}, acc), validator(control.value))); }, {})) || {};
132
- return __assign(__assign({}, acc), (_b = {}, _b[key] = __assign(__assign({}, control), { validatorErrors: validatorErrors }), _b));
133
- }, {});
134
- return validated;
135
+ var getErrors = function (control, value) {
136
+ var _a;
137
+ return ((_a = control.config.validators) === null || _a === void 0 ? void 0 : _a.reduce(function (acc, validator) { return (__assign(__assign({}, acc), validator(value))); }, {})) || {};
135
138
  };
136
139
 
137
140
  var buildState = function (config, form, controlRef) {
@@ -149,7 +152,7 @@ var buildState = function (config, form, controlRef) {
149
152
  config: config,
150
153
  key: generateKey(5)
151
154
  };
152
- var newForm = __assign(__assign({}, form), (_a = {}, _a[getFormKey(controlRef)] = control, _a));
155
+ var newForm = __assign(__assign({}, form), (_a = {}, _a[getFormKey(controlRef)] = __assign(__assign({}, control), { validatorErrors: getErrors(control, value) }), _a));
153
156
  var controls = config.controls;
154
157
  // Adding controls for Form Group
155
158
  if (controls && !(controls instanceof Array)) {
@@ -168,7 +171,7 @@ var buildFormState = function (config, form, controlRef) {
168
171
  if (form === void 0) { form = { root: null }; }
169
172
  if (controlRef === void 0) { controlRef = []; }
170
173
  return {
171
- form: syncValidate(buildState(config, form, controlRef)),
174
+ form: buildState(config, form, controlRef),
172
175
  action: null
173
176
  };
174
177
  };
@@ -277,6 +280,7 @@ var buildHub2Source = function (rx) {
277
280
  case 'updateValues':
278
281
  controlsToCheck = getControlBranch(action.payload.controlRef, newForm);
279
282
  break;
283
+ case 'pushControl':
280
284
  case 'addControl':
281
285
  var changedControl = getControl(action.payload.controlRef, newForm);
282
286
  if (Array.isArray(changedControl.config.controls)) {
@@ -304,11 +308,6 @@ var buildHub2Source = function (rx) {
304
308
  return sourceForHub2$;
305
309
  };
306
310
 
307
- var getErrors = function (control, value) {
308
- var _a;
309
- return ((_a = control.config.validators) === null || _a === void 0 ? void 0 : _a.reduce(function (acc, validator) { return (__assign(__assign({}, acc), validator(value))); }, {})) || {};
310
- };
311
-
312
311
  var UPDATE_ANCESTOR_VALUES = 'UPDATE_ANCESTOR_VALUES';
313
312
  var updateAncestorValues = function (form, _a) {
314
313
  var _b, _c;
@@ -527,6 +526,28 @@ var addControl = function (state, action) {
527
526
  return { form: ancestorsUpdated, action: action };
528
527
  };
529
528
 
529
+ var pushControl = function (state, action) {
530
+ var newControlRef;
531
+ var _a = action.payload, config = _a.config, controlRef = _a.controlRef;
532
+ var existingControl = getControl(controlRef, state.form);
533
+ if (!existingControl)
534
+ throw 'You are attempting to push to a control that does not exist';
535
+ // If controlRef exists we are adding control to a Form Array
536
+ if (Array.isArray(existingControl.config.controls)) {
537
+ newControlRef = controlRef.concat(existingControl.value.length);
538
+ }
539
+ else {
540
+ throw 'You are attempting to push to a control that is not a Form Array';
541
+ }
542
+ var newForm = buildState(config, state.form, newControlRef);
543
+ var newValue = getControl(newControlRef, newForm).value;
544
+ var ancestorsUpdated = updateAncestorValuesAddControl(newForm, {
545
+ type: UPDATE_ANCESTOR_VALUES_ADD_CONTROL,
546
+ payload: { controlRef: newControlRef, value: newValue }
547
+ });
548
+ return { form: ancestorsUpdated, action: action };
549
+ };
550
+
530
551
  // Same implementation as updateAncestor values except updating pristine values
531
552
  var UPDATE_ANCESTOR_PRISTINE_VALUES = 'UPDATE_ANCESTOR_PRISTINE_VALUES';
532
553
  var updateAncestorPristineValues = function (form, _a) {
@@ -651,7 +672,7 @@ var asyncValidation = function (form, _a) {
651
672
  return __assign(__assign({}, form), updatedSelfAndAncestors);
652
673
  };
653
674
 
654
- var hasErrors$1 = function (errors) {
675
+ var hasErrors$4 = function (errors) {
655
676
  return Object.values(errors).some(function (hasError) { return hasError; });
656
677
  };
657
678
  var mergeBranchErrors = function (form, controlRef) {
@@ -665,7 +686,7 @@ var mergeBranchErrors = function (form, controlRef) {
665
686
  var _b;
666
687
  var key = _a[0], control = _a[1];
667
688
  var errors = __assign(__assign({}, control.validatorErrors), control.asyncValidatorErrors);
668
- var selfValid = !hasErrors$1(errors);
689
+ var selfValid = !hasErrors$4(errors);
669
690
  var childrenValid = true;
670
691
  if (Array.isArray(control.config.controls)) {
671
692
  // If control is a FormArray
@@ -683,7 +704,7 @@ var mergeBranchErrors = function (form, controlRef) {
683
704
  return valid;
684
705
  });
685
706
  }
686
- return __assign(__assign({}, acc), (_b = {}, _b[key] = __assign(__assign({}, control), { errors: errors, valid: selfValid && childrenValid }), _b));
707
+ return __assign(__assign({}, acc), (_b = {}, _b[key] = __assign(__assign({}, control), { errors: errors, valid: selfValid && childrenValid, childrenValid: childrenValid }), _b));
687
708
  }, {});
688
709
  return __assign(__assign({}, form), errorsMerged);
689
710
  };
@@ -717,7 +738,7 @@ var asyncValidationResponseSuccess = function (form, _a) {
717
738
  return mergeBranchErrors(ancestorsUpdated, control.controlRef);
718
739
  };
719
740
 
720
- var hasErrors = function (errors) {
741
+ var hasErrors$3 = function (errors) {
721
742
  return Object.values(errors).some(function (hasError) { return hasError; });
722
743
  };
723
744
  // TODO: update merge errors to not do the entire form but just a subset of it
@@ -729,7 +750,7 @@ var mergeErrors = function (form) {
729
750
  var _b;
730
751
  var key = _a[0], control = _a[1];
731
752
  var errors = __assign(__assign({}, control.validatorErrors), control.asyncValidatorErrors);
732
- var selfValid = !hasErrors(errors);
753
+ var selfValid = !hasErrors$3(errors);
733
754
  var childrenValid = true;
734
755
  if (Array.isArray(control.config.controls)) {
735
756
  // If control is a FormArray
@@ -739,7 +760,7 @@ var mergeErrors = function (form) {
739
760
  // If control is a FormGroup
740
761
  childrenValid = Object.keys(control.value).every(function (childKey) { return acc[getFormKey(control.controlRef.concat(childKey))].valid; });
741
762
  }
742
- return __assign(__assign({}, acc), (_b = {}, _b[key] = __assign(__assign({}, control), { errors: errors, valid: selfValid && childrenValid }), _b));
763
+ return __assign(__assign({}, acc), (_b = {}, _b[key] = __assign(__assign({}, control), { errors: errors, valid: selfValid && childrenValid, childrenValid: childrenValid }), _b));
743
764
  }, {});
744
765
  var restoredOrder = Object.keys(errorsMerged)
745
766
  .reverse()
@@ -750,29 +771,80 @@ var mergeErrors = function (form) {
750
771
  return restoredOrder;
751
772
  };
752
773
 
774
+ var hasErrors$2 = function (errors) {
775
+ return Object.values(errors).some(function (hasError) { return hasError; });
776
+ };
753
777
  var mergeValueUpdated = function (state, form, controlRef) {
754
- var controlBranch = getControlBranch(controlRef, form).reduce(function (acc, control) {
778
+ var controlBranch = getControlBranch(controlRef, form)
779
+ .reverse()
780
+ .reduce(function (acc, control) {
755
781
  var _a;
756
782
  var key = getFormKey(control.controlRef);
757
- return __assign(__assign({}, acc), (_a = {}, _a[key] = __assign(__assign({}, state[key]), control), _a));
783
+ var existingControl = state[key] || structuredClone(DEFAULT_HUB2_FIELDS);
784
+ var errors = __assign(__assign({}, control.validatorErrors), existingControl.asyncValidatorErrors);
785
+ var selfValid = !hasErrors$2(errors);
786
+ var childrenValid = true;
787
+ if (Array.isArray(control.config.controls)) {
788
+ // If control is a FormArray
789
+ childrenValid = control.value.every(function (item, index) {
790
+ var formKey = getFormKey(control.controlRef.concat(index));
791
+ var valid = acc[formKey] === undefined ? state[formKey].valid : acc[formKey].valid;
792
+ return valid;
793
+ });
794
+ }
795
+ else if (control.config.controls) {
796
+ // If control is a FormGroup
797
+ childrenValid = Object.keys(control.value).every(function (childKey) {
798
+ var formKey = getFormKey(control.controlRef.concat(childKey));
799
+ var valid = acc[formKey] === undefined ? state[formKey].valid : acc[formKey].valid;
800
+ return valid;
801
+ });
802
+ }
803
+ return __assign(__assign({}, acc), (_a = {}, _a[key] = __assign(__assign(__assign({}, existingControl), control), { errors: errors, valid: selfValid && childrenValid, childrenValid: childrenValid }), _a));
758
804
  }, {});
759
- return mergeBranchErrors(__assign(__assign({}, state), controlBranch), controlRef);
805
+ return __assign(__assign({}, state), controlBranch);
760
806
  };
761
807
 
808
+ var hasErrors$1 = function (errors) {
809
+ return Object.values(errors).some(function (hasError) { return hasError; });
810
+ };
762
811
  var mergeRemoveControl = function (state, form, controlRef) {
763
812
  var parentRef = controlRef.slice(0, -1);
764
- var controlBranch = getControlBranch(parentRef, form).reduce(function (acc, baseControl) {
813
+ var existingBranch = getControlBranch(parentRef, state);
814
+ var descendants = existingBranch.filter(function (control) { return control.controlRef.length < parentRef.length; });
815
+ var controlBranch = getControlBranch(parentRef, form)
816
+ .reverse()
817
+ .reduce(function (acc, baseControl) {
765
818
  var _a;
766
819
  var key = getFormKey(baseControl.controlRef);
767
- var existingControl = getControlBranch(parentRef, state).find(function (control) { return baseControl.key === control.key; });
768
- return __assign(__assign({}, acc), (_a = {}, _a[key] = __assign(__assign({}, existingControl), baseControl), _a));
820
+ var existingControl = existingBranch.find(function (control) { return baseControl.key === control.key; }) ||
821
+ structuredClone(DEFAULT_HUB2_FIELDS);
822
+ var errors = __assign(__assign({}, baseControl.validatorErrors), existingControl.asyncValidatorErrors);
823
+ var selfValid = !hasErrors$1(errors);
824
+ var childrenValid = true;
825
+ if (Array.isArray(baseControl.config.controls)) {
826
+ // If control is a FormArray
827
+ childrenValid = baseControl.value.every(function (item, index) {
828
+ var formKey = getFormKey(baseControl.controlRef.concat(index));
829
+ var valid = acc[formKey] === undefined ? state[formKey].valid : acc[formKey].valid;
830
+ return valid;
831
+ });
832
+ }
833
+ else if (baseControl.config.controls) {
834
+ // If control is a FormGroup
835
+ childrenValid = Object.keys(baseControl.value).every(function (childKey) {
836
+ var formKey = getFormKey(baseControl.controlRef.concat(childKey));
837
+ var valid = acc[formKey] === undefined ? state[formKey].valid : acc[formKey].valid;
838
+ return valid;
839
+ });
840
+ }
841
+ return __assign(__assign({}, acc), (_a = {}, _a[key] = __assign(__assign(__assign({}, existingControl), baseControl), { errors: errors, valid: selfValid && childrenValid, childrenValid: childrenValid }), _a));
769
842
  }, {});
770
843
  var removedControls = __assign({}, state);
771
- var descendants = getDescendantControls(parentRef, state);
772
844
  descendants.forEach(function (control) {
773
845
  delete removedControls[getFormKey(control.controlRef)];
774
846
  });
775
- return mergeBranchErrors(__assign(__assign({}, removedControls), controlBranch), parentRef);
847
+ return __assign(__assign({}, removedControls), controlBranch);
776
848
  };
777
849
 
778
850
  var mergeTouchUpdated = function (state, form, controlRef) {
@@ -784,13 +856,46 @@ var mergeTouchUpdated = function (state, form, controlRef) {
784
856
  return __assign(__assign({}, state), controlBranch);
785
857
  };
786
858
 
787
- var DEFAULT_HUB2_FIELDS = {
788
- asyncValidatorErrors: {},
789
- asyncValidateInProgress: {},
790
- pending: false,
791
- valid: null,
792
- errors: null
859
+ var hasErrors = function (errors) {
860
+ return Object.values(errors).some(function (hasError) { return hasError; });
793
861
  };
862
+ var mergePushControl = function (state, form, controlRef) {
863
+ var baseFormArray = getControl(controlRef, form);
864
+ //If Form Array
865
+ // use the added control (last index)
866
+ // merge descendants with default stuff
867
+ var newItemIndex = baseFormArray.value.length - 1;
868
+ var descendants = getDescendantControls(controlRef.concat(newItemIndex), form);
869
+ var mergedDescendants = mergeErrors(descendants.reduce(function (acc, control) {
870
+ var _a;
871
+ var formKey = getFormKey(control.controlRef);
872
+ return __assign(__assign({}, acc), (_a = {}, _a[formKey] = __assign(__assign({}, control), structuredClone(DEFAULT_HUB2_FIELDS)), _a));
873
+ }, {}));
874
+ var ancestors = getAncestorControls(controlRef, state)
875
+ .reverse()
876
+ .reduce(function (acc, control, index, arr) {
877
+ var _a, _b;
878
+ var formKey = getFormKey(control.controlRef);
879
+ var errors = __assign(__assign({}, form[formKey].validatorErrors), control.asyncValidatorErrors);
880
+ if (!control.childrenValid)
881
+ // If the ancestor control's children were not valid, pushing an item won't change its valid status
882
+ return __assign(__assign({}, acc), (_a = {}, _a[formKey] = __assign(__assign(__assign({}, control), form[formKey]), { errors: errors }), _a));
883
+ var selfValid = !hasErrors(errors);
884
+ var childrenValid = true;
885
+ if (index === 0) {
886
+ childrenValid =
887
+ control.childrenValid &&
888
+ mergedDescendants[getFormKey(controlRef.concat(newItemIndex))].valid;
889
+ }
890
+ else {
891
+ childrenValid = control.childrenValid && arr[index - 1].valid;
892
+ }
893
+ return __assign(__assign({}, acc), (_b = {}, _b[formKey] = __assign(__assign(__assign({}, control), form[formKey]), { errors: errors, valid: selfValid && childrenValid, childrenValid: childrenValid }), _b));
894
+ }, {});
895
+ var controlBranchUpdated = __assign(__assign({}, ancestors), mergedDescendants);
896
+ return __assign(__assign({}, state), controlBranchUpdated);
897
+ };
898
+
794
899
  var formChange = function (state, _a) {
795
900
  if (state === void 0) { state = null; }
796
901
  var _b = _a.payload, form = _b.form, action = _b.action;
@@ -802,8 +907,10 @@ var formChange = function (state, _a) {
802
907
  }, {}));
803
908
  }
804
909
  switch (action === null || action === void 0 ? void 0 : action.type) {
805
- case 'updateValues':
910
+ case 'pushControl':
911
+ return mergePushControl(state, form, action.payload.controlRef);
806
912
  case 'addControl':
913
+ case 'updateValues':
807
914
  return mergeValueUpdated(state, form, action.payload.controlRef);
808
915
  case 'resetControl':
809
916
  case 'removeControl':
@@ -817,9 +924,7 @@ var formChange = function (state, _a) {
817
924
  return mergeErrors(Object.entries(form).reduce(function (acc, _a) {
818
925
  var _b;
819
926
  var dictKey = _a[0], baseControl = _a[1];
820
- var existingControl = (action === null || action === void 0 ? void 0 : action.type) === 'removeControl'
821
- ? state && Object.values(state).find(function (control) { return baseControl.key === control.key; })
822
- : state && state[dictKey];
927
+ var existingControl = state && state[dictKey];
823
928
  return __assign(__assign({}, acc), (_b = {}, _b[dictKey] = __assign(__assign({}, (existingControl
824
929
  ? existingControl
825
930
  : structuredClone(DEFAULT_HUB2_FIELDS))), baseControl), _b));
@@ -849,6 +954,7 @@ var build = function (config, options) {
849
954
  updateValues: updateValues,
850
955
  removeControl: removeControl,
851
956
  addControl: addControl,
957
+ pushControl: pushControl,
852
958
  markControlAsPristine: markControlAsPristine,
853
959
  markControlAsTouched: markControlAsTouched,
854
960
  markControlAsUntouched: markControlAsUntouched,
package/package.json CHANGED
@@ -14,12 +14,12 @@
14
14
  "author": "David Lai",
15
15
  "license": "ISC",
16
16
  "dependencies": {
17
- "@reactables/core": "^0.4.5-alpha.0",
17
+ "@reactables/core": "^0.5.0-alpha.0",
18
18
  "lodash.clonedeep": "^4.5.0",
19
19
  "lodash.isequal": "^4.5.0"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "rxjs": "^6.0.0 || ^7.0.0"
23
23
  },
24
- "version": "0.4.5-alpha.0"
24
+ "version": "0.5.0-alpha.0"
25
25
  }
@@ -1,2 +0,0 @@
1
- import { BaseForm } from '../../Models/Controls';
2
- export declare const syncValidate: <T>(form: BaseForm<T>) => BaseForm<T>;
@@ -1 +0,0 @@
1
- export {};