@domonda/form
Advanced tools
Comparing version 1.0.2 to 1.1.0
@@ -6,2 +6,26 @@ # Change Log | ||
# [1.1.0](https://github.com/domonda/domonda-js/compare/@domonda/form@1.0.2...@domonda/form@1.1.0) (2019-07-17) | ||
### Bug Fixes | ||
* **FormField:** correctly handle change ([f9ce7dd](https://github.com/domonda/domonda-js/commit/f9ce7dd)) | ||
* **FormField:** pass validation tests ([719c20c](https://github.com/domonda/domonda-js/commit/719c20c)) | ||
* **FormField:** values should not be on the form field ([1609abb](https://github.com/domonda/domonda-js/commit/1609abb)) | ||
* dispatched submit is cancelable ([cada13a](https://github.com/domonda/domonda-js/commit/cada13a)) | ||
### Features | ||
* **validation:** debounce only if necessary ([187d9c2](https://github.com/domonda/domonda-js/commit/187d9c2)) | ||
### Performance Improvements | ||
* **FormField:** store curr validaiton message locally ([b9afc91](https://github.com/domonda/domonda-js/commit/b9afc91)) | ||
## [1.0.2](https://github.com/domonda/domonda-js/compare/@domonda/form@1.0.1...@domonda/form@1.0.2) (2019-07-09) | ||
@@ -8,0 +32,0 @@ |
@@ -98,3 +98,3 @@ "use strict"; | ||
else if (configRef.current.el.reportValidity()) { | ||
configRef.current.el.dispatchEvent(new Event('submit')); | ||
configRef.current.el.dispatchEvent(new Event('submit', { cancelable: true })); | ||
} | ||
@@ -101,0 +101,0 @@ }); |
@@ -7,10 +7,2 @@ "use strict"; | ||
*/ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __rest = (this && this.__rest) || function (s, e) { | ||
@@ -36,6 +28,7 @@ var t = {}; | ||
const omit_1 = __importDefault(require("lodash/fp/omit")); | ||
const pick_1 = __importDefault(require("lodash/fp/pick")); | ||
const Subject_1 = require("rxjs/internal/Subject"); | ||
// $ | ||
const operators_1 = require("rxjs/operators"); | ||
function deriveState(path, state) { | ||
function deriveState(path, state, isLocalNext) { | ||
const { fields, defaultValues, values } = state; | ||
@@ -48,2 +41,6 @@ const field = fields[path]; | ||
const value = get_1.default(values, path); | ||
if (isLocalNext) { | ||
return Object.assign({}, field, { defaultValue, | ||
value }); | ||
} | ||
return Object.assign({}, field, { defaultValue, | ||
@@ -60,5 +57,11 @@ value, changed: !equality_1.equal(defaultValue, value) }); | ||
} }) })); | ||
// a flag which prevents double checking the value equality | ||
// when the field sends the next signal. if the form sends a new | ||
// value then the check will be performed while deriving the state | ||
let localNext = false; | ||
const $ = new Subject_1.AnonymousSubject({ | ||
next: (field) => { | ||
form$.next(Object.assign({}, form$.value, { values: setWith_1.default(clone_1.default, path, field.value, form$.value.values), fields: Object.assign({}, form$.value.fields, { [path]: field }) })); | ||
localNext = true; | ||
form$.next(Object.assign({}, form$.value, { values: setWith_1.default(clone_1.default, path, field.value, form$.value.values), fields: Object.assign({}, form$.value.fields, { [path]: pick_1.default(['changed', 'validityMessage'], field) }) })); | ||
localNext = false; | ||
}, | ||
@@ -75,3 +78,3 @@ error: () => { | ||
// its just a type hack so that we dont assert everywhere else... | ||
operators_1.map((state) => deriveState(path, state)), | ||
operators_1.map((state) => deriveState(path, state, localNext)), | ||
// complete stream when the field gets removed | ||
@@ -83,12 +86,23 @@ operators_1.takeWhile((state) => !!state), | ||
if (validate) { | ||
const validator = validateDebounce > 0 | ||
? $.pipe( | ||
// we skip the first iteration since we don't want to invalidate initially | ||
operators_1.skip(immediateValidate ? 0 : 1), | ||
// we don't care about the validity, just the value | ||
operators_1.distinctUntilChanged(({ value: prev }, { value: curr }) => equality_1.equal(prev, curr)), operators_1.debounceTime(validateDebounce)) | ||
: $.pipe( | ||
// we skip the first iteration since we don't want to invalidate initially | ||
operators_1.skip(immediateValidate ? 0 : 1), | ||
// we don't care about the validity, just the value | ||
operators_1.distinctUntilChanged(({ value: prev }, { value: curr }) => equality_1.equal(prev, curr))); | ||
let currValidationMessage = null; | ||
let counter = 0; | ||
$.pipe( | ||
// we skip the first iteration since we don't want to invalidate initially | ||
operators_1.skip(immediateValidate ? 0 : 1), | ||
// we don't care about the validity, just the value | ||
operators_1.distinctUntilChanged(({ value: prev }, { value: curr }) => equality_1.equal(prev, curr)), operators_1.debounceTime(validateDebounce)).subscribe((state) => __awaiter(this, void 0, void 0, function* () { | ||
const _a = state, { value, validityMessage } = _a, rest = __rest(_a, ["value", "validityMessage"]); | ||
validator.subscribe((state) => | ||
// we perform the validation after all subscribers have been notified about the value change | ||
setTimeout(() => { | ||
const _a = state, { value } = _a, rest = __rest(_a, ["value"]); | ||
const pendingValidityMessage = validate(value); | ||
if (!(pendingValidityMessage instanceof Promise)) { | ||
if (pendingValidityMessage !== validityMessage) { | ||
if (pendingValidityMessage !== currValidationMessage) { | ||
currValidationMessage = pendingValidityMessage; | ||
$.next(Object.assign({}, rest, { value, validityMessage: pendingValidityMessage })); | ||
@@ -101,14 +115,17 @@ } | ||
counter++; | ||
if (validityMessage !== undefined) { | ||
$.next(Object.assign({}, rest, { value, validityMessage: undefined })); | ||
if (currValidationMessage !== undefined) { | ||
currValidationMessage = undefined; | ||
$.next(Object.assign({}, rest, { value, validityMessage: currValidationMessage })); | ||
} | ||
const nextValidityMessage = yield pendingValidityMessage; | ||
// if the internalCounter does not match the outer counter that means that another, newer, validity check is pending | ||
if (internalCounter + 1 === counter) { | ||
$.next(Object.assign({}, rest, { value, validityMessage: nextValidityMessage })); | ||
} | ||
})); | ||
pendingValidityMessage.then((nextValidityMessage) => { | ||
// if the internalCounter does not match the outer counter that means that another, newer, validity check is pending | ||
if (internalCounter + 1 === counter) { | ||
currValidationMessage = nextValidityMessage; | ||
$.next(Object.assign({}, rest, { value, validityMessage: nextValidityMessage })); | ||
} | ||
}); | ||
}, 0)); | ||
} | ||
function getState() { | ||
const state = deriveState(path, form$.value); | ||
const state = deriveState(path, form$.value, false); | ||
if (!state) { | ||
@@ -132,7 +149,8 @@ throw new Error('domonda-form: Field state should be available here!'); | ||
setValue: (nextValue) => { | ||
$.next(Object.assign({}, getState(), { value: nextValue })); | ||
const curr = getState(); | ||
$.next(Object.assign({}, curr, { changed: !equality_1.equal(curr.defaultValue, nextValue), value: nextValue })); | ||
}, | ||
resetValue: () => { | ||
const curr = getState(); | ||
$.next(Object.assign({}, curr, { value: curr.defaultValue })); | ||
$.next(Object.assign({}, curr, { changed: false, value: curr.defaultValue })); | ||
}, | ||
@@ -139,0 +157,0 @@ }, |
@@ -15,3 +15,3 @@ /** | ||
export declare type FormDefaultValues = object; | ||
export declare type FormSubmitHandler<T extends FormDefaultValues> = (values: T, form: Form<T>) => void; | ||
export declare type FormSubmitHandler<T extends FormDefaultValues> = (values: T, form: Form<T>) => void | Promise<void>; | ||
export interface FormConfig<T extends FormDefaultValues> { | ||
@@ -18,0 +18,0 @@ /** If the submit succeeds, reset the values to the `defaultValues`. */ |
{ | ||
"name": "@domonda/form", | ||
"version": "1.0.2", | ||
"version": "1.1.0", | ||
"description": "Powerful yet simple form library built on top of RxJS.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
23132
489