Skip to content

Commit

Permalink
feat: updated onChange hook behavior and fixes
Browse files Browse the repository at this point in the history
updated onChange hook behavior and fixes

fix #337
  • Loading branch information
foxhound87 committed Apr 2, 2023
1 parent 7f20503 commit 8e417a3
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 114 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# 5.8.0 (next)

- `set()` method will increase `changed` prop and trigger `onChange` Event Hook
- Mobx events (observe/intercept) allowed props guarded.
- Introduced `onSync` Hook (triggered on `onChange` Event Handler)
- Introduced `validateOnSubmit` form option (active by default).
- Fix: `ref` prop for separated props mode renamed to `refs` (plural)
- Fix: #337
# 5.7.1 (next)

- fix: allow `ref` prop on `set()`
Expand Down
113 changes: 65 additions & 48 deletions src/Base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import FieldInterface from "./models/FieldInterface";
import {
props,
allowedProps,
checkPropType,
checkPropOccurrence,
throwError,
isArrayOfObjects,
getObservableMapValues,
Expand All @@ -37,8 +37,9 @@ import {
pathToFieldsTree,
defaultClearValue,
} from "./parser";
import { FieldPropsEnum } from "./models/FieldProps";
import { AllowedFieldPropsTypes, FieldPropsEnum, SeparatedPropsMode } from "./models/FieldProps";
import { OptionsEnum } from "./models/OptionsModel";
import { ValidationHooks } from "./models/ValidatorInterface";
export default class Base implements BaseInterface {
noop = () => {};

Expand Down Expand Up @@ -258,29 +259,29 @@ export default class Base implements BaseInterface {
};

const props = {
$value: _.get(initial["values"], path),
$label: _try("labels"),
$placeholder: _try("placeholders"),
$default: _try("defaults"),
$initial: _try("initials"),
$disabled: _try("disabled"),
$deleted: _try("deleted"),
$type: _try("types"),
$related: _try("related"),
$rules: _try("rules"),
$options: _try("options"),
$bindings: _try("bindings"),
$extra: _try("extra"),
$hooks: _try("hooks"),
$handlers: _try("handlers"),
$validatedWith: _try("validatedWith"),
$validators: _try("validators"),
$observers: _try("observers"),
$interceptors: _try("interceptors"),
$input: _try("input"),
$output: _try("output"),
$autoFocus: _try("autoFocus"),
$ref: _try("ref"),
$value: _.get(initial[SeparatedPropsMode.values], path),
$label: _try(SeparatedPropsMode.labels),
$placeholder: _try(SeparatedPropsMode.placeholders),
$default: _try(SeparatedPropsMode.defaults),
$initial: _try(SeparatedPropsMode.initials),
$disabled: _try(SeparatedPropsMode.disabled),
$deleted: _try(SeparatedPropsMode.deleted),
$type: _try(SeparatedPropsMode.types),
$related: _try(SeparatedPropsMode.related),
$rules: _try(SeparatedPropsMode.rules),
$options: _try(SeparatedPropsMode.options),
$bindings: _try(SeparatedPropsMode.bindings),
$extra: _try(SeparatedPropsMode.extra),
$hooks: _try(SeparatedPropsMode.hooks),
$handlers: _try(SeparatedPropsMode.handlers),
$validatedWith: _try(SeparatedPropsMode.validatedWith),
$validators: _try(SeparatedPropsMode.validators),
$observers: _try(SeparatedPropsMode.observers),
$interceptors: _try(SeparatedPropsMode.interceptors),
$input: _try(SeparatedPropsMode.input),
$output: _try(SeparatedPropsMode.output),
$autoFocus: _try(SeparatedPropsMode.autoFocus),
$ref: _try(SeparatedPropsMode.refs),
};

const field = this.state.form.makeField({
Expand Down Expand Up @@ -314,8 +315,16 @@ export default class Base implements BaseInterface {
this.$submitting = true;
this.$submitted += 1;

const exec = (isValid: boolean) =>
isValid ? this.execHook("onSuccess", o) : this.execHook("onError", o);
if (!this.state.options.get(OptionsEnum.validateOnSubmit, this)) {
return Promise
.resolve(this)
.then(action(() => (this.$submitting = false)))
.then(() => this);
}

const exec = (isValid: boolean) => isValid
? this.execHook(ValidationHooks.onSuccess, o)
: this.execHook(ValidationHooks.onError, o);

return (
this.validate({
Expand Down Expand Up @@ -345,12 +354,12 @@ export default class Base implements BaseInterface {
Check Field Computed Values
*/
check(prop: string, deep: boolean = false): boolean {
allowedProps("computed", [prop]);
allowedProps(AllowedFieldPropsTypes.computed, [prop]);

return deep
? checkPropType({
type: props.types[prop],
data: this.deepCheck(props.types[prop], prop, this.fields),
? checkPropOccurrence({
type: props.occurrences[prop],
data: this.deepCheck(props.occurrences[prop], prop, this.fields),
})
: (this as any)[prop];
}
Expand All @@ -365,7 +374,7 @@ export default class Base implements BaseInterface {
}

const $deep = this.deepCheck(type, prop, field.fields);
check.push(checkPropType({ type, data: $deep }));
check.push(checkPropOccurrence({ type, data: $deep }));
return check;
},
[]
Expand Down Expand Up @@ -458,7 +467,7 @@ export default class Base implements BaseInterface {
);
}

allowedProps("all", _.isArray(prop) ? prop : [prop]);
allowedProps(AllowedFieldPropsTypes.all, _.isArray(prop) ? prop : [prop]);

if (_.isString(prop)) {
if (strict && this.fields.size === 0) {
Expand Down Expand Up @@ -536,14 +545,16 @@ export default class Base implements BaseInterface {
set(prop: any, data?: any): void {
// UPDATE CUSTOM PROP
if (_.isString(prop) && !_.isUndefined(data)) {
allowedProps("field", [prop]);
allowedProps(AllowedFieldPropsTypes.editable, [prop]);
const deep = (_.isObject(data) && prop === FieldPropsEnum.value) || _.isPlainObject(data);
if (deep && this.hasNestedFields) this.deepSet(prop, data, "", true);
else _.set(this, `$${prop}`, data);

if (deep && this.hasNestedFields) return this.deepSet(prop, data, "", true);
// else _.set(this, `$${prop}`, data);
if (prop === FieldPropsEnum.value) {
this.$changed ++;
this.state.form.$changed ++;
(this as any).value = parseInput((this as any).$input, {
separated: data,
});
} else {
_.set(this, `$${prop}`, data);
}
return;
}
Expand Down Expand Up @@ -667,7 +678,15 @@ export default class Base implements BaseInterface {
/**
MobX Event (observe/intercept)
*/
MOBXEvent({ path = null, key = FieldPropsEnum.value, call, type }: any): void {
MOBXEvent({
prop = FieldPropsEnum.value,
key = null,
path = null,
call,
type
}: any): void {
let $prop = key || prop;
allowedProps(AllowedFieldPropsTypes.observable, [$prop]);
const $instance = this.select(path || this.path, null, null) || this;

const $call = (change: any) =>
Expand All @@ -685,23 +704,21 @@ export default class Base implements BaseInterface {

if (type === "observer") {
fn = observe;
ffn = (cb: any) => observe($instance.fields, cb);
ffn = (cb: any) => observe($instance.fields, cb); // fields
}

if (type === "interceptor") {
// eslint-disable-next-line
key = `$${key}`;
$prop = `$${prop}`;
fn = intercept;
ffn = $instance.fields.intercept;
ffn = $instance.fields.intercept; // fields
}

const $dkey = $instance.path ? `${key}@${$instance.path}` : key;
const $dkey = $instance.path ? `${$prop}@${$instance.path}` : $prop;

_.merge(this.state.disposers[type], {
[$dkey]:
key === FieldPropsEnum.fields
$prop === FieldPropsEnum.fields
? ffn.apply((change: any) => $call(change))
: (fn as any)($instance, key, (change: any) => $call(change)),
: (fn as any)($instance, $prop, (change: any) => $call(change)),
});
}

Expand Down
12 changes: 7 additions & 5 deletions src/Field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default class Field extends Base implements FieldInterface {
disposeValidationOnChange: any;

files: any;

constructor({
key,
path,
Expand Down Expand Up @@ -225,9 +226,8 @@ export default class Field extends Base implements FieldInterface {

this.execHook(FieldPropsEnum.onInit);

// handle Field onChange Hook for nested fields
this.hasNestedFields
&& autorun(() => this.changed && this.execHook(FieldPropsEnum.onChange));
// handle Field onChange Hook
autorun(() => this.changed && this.execHook(FieldPropsEnum.onChange));
}

/* ------------------------------------------------------------------ */
Expand Down Expand Up @@ -436,10 +436,12 @@ export default class Field extends Base implements FieldInterface {
this.value = e;
});

onChange = (...args: any) =>
onSync = (...args: any) =>
this.type === "file"
? this.onDrop(...args)
: this.execHandler(FieldPropsEnum.onChange, args, this.sync);
: this.execHandler(FieldPropsEnum.onSync, args, this.sync);

onChange = this.onSync;

onToggle = (...args: any) =>
this.execHandler(FieldPropsEnum.onToggle, args, this.sync);
Expand Down
7 changes: 2 additions & 5 deletions src/Form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import State from "./State";
import Field from "./Field";
import ValidatorInterface from "./models/ValidatorInterface";
import FieldInterface, { FieldConstructor } from "./models/FieldInterface";
import FormInterface, {
FieldsDefinitions,
FormConfig,
} from "./models/FormInterface";
import FormInterface, { FieldsDefinitions, FormConfig } from "./models/FormInterface";
import { FieldPropsEnum } from "./models/FieldProps";
import { OptionsEnum } from "./models/OptionsModel";

Expand Down Expand Up @@ -166,7 +163,7 @@ export default class Form extends Base implements FormInterface {
return new Field(data);
}

/**
/** DEPRECATED
Init Form Fields and Nested Fields
init($fields: any = null): void {
Expand Down
1 change: 1 addition & 0 deletions src/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default class Options implements OptionsInterface {
showErrorsOnClear: false,
showErrorsOnReset: true,
validateOnInit: true,
validateOnSubmit: true,
validateOnBlur: true,
validateOnChange: false,
validateOnChangeAfterInitialBlur: false,
Expand Down
1 change: 1 addition & 0 deletions src/models/FieldInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default interface FieldInterface extends BaseInterface {
touched: boolean;
deleted: boolean;
// handlers
onSync(args: any): any;
onChange(args: any): any;
onToggle(args: any): any;
onBlur(args: any): any;
Expand Down
39 changes: 39 additions & 0 deletions src/models/FieldProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export enum FieldPropsEnum {
hasError = "hasError",
// handlers
onInit = "onInit",
onSync = "onSync",
onChange = "onChange",
onBlur = "onBlur",
onFocus = "onFocus",
Expand All @@ -61,3 +62,41 @@ export enum FieldPropsEnum {
export type FieldPropsType = {
[key in FieldPropsEnum]?: any;
}

export enum AllowedFieldPropsTypes {
computed = 'computed',
observable = 'observable',
editable = 'editable',
all = 'all',
}

export enum FieldPropsOccurrence {
some = 'some',
every = 'every',
}

export enum SeparatedPropsMode {
values = 'values',
labels = 'labels',
placeholders = 'placeholders',
defaults = 'defaults',
initials = 'initials',
disabled = 'disabled',
deleted = 'deleted',
types = 'types',
related = 'related',
rules = 'rules',
options = 'options',
bindings = 'bindings',
extra = 'extra',
hooks = 'hooks',
handlers = 'handlers',
validatedWith = 'validatedWith',
validators = 'validators',
observers = 'observers',
interceptors = 'interceptors',
input = 'input',
output = 'output',
autoFocus = 'autoFocus',
refs = 'refs',
}
2 changes: 2 additions & 0 deletions src/models/OptionsModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export enum OptionsEnum {
showErrorsOnClear = 'showErrorsOnClear',
showErrorsOnReset = 'showErrorsOnReset',
validateOnInit = 'validateOnInit',
validateOnSubmit = 'validateOnSubmit',
validateOnBlur = 'validateOnBlur',
validateOnChange = 'validateOnChange',
validateOnChangeAfterInitialBlur = 'validateOnChangeAfterInitialBlur',
Expand Down Expand Up @@ -47,6 +48,7 @@ export default interface OptionsModel {
[OptionsEnum.showErrorsOnClear]?: boolean;
[OptionsEnum.showErrorsOnReset]?: boolean;
[OptionsEnum.validateOnInit]?: boolean;
[OptionsEnum.validateOnSubmit]?: boolean;
[OptionsEnum.validateOnBlur]?: boolean;
[OptionsEnum.validateOnChange]?: boolean;
[OptionsEnum.validateOnChangeAfterInitialBlur]?: boolean;
Expand Down
5 changes: 5 additions & 0 deletions src/models/ValidatorInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,8 @@ export interface ValidationPluginInterface extends ValidationPluginConstructor {
export interface DriversMap {
[index: string]: ValidationPluginInterface;
}

export enum ValidationHooks {
onSuccess = 'onSuccess',
onError = 'onError',
}
Loading

0 comments on commit 8e417a3

Please sign in to comment.