UNPKG

d2-ui

Version:
95 lines (85 loc) 4.23 kB
import { Observable, Subject } from 'rxjs'; /** * Run `validatorFunctions` in parallel and returns a resolved `Promise` with the validation status. * @param {function:Promise[]} validatorFunctions Array of validator functions that return a Promise. * @param {*} value The value that should be checked by the given validators * @returns {Promise.<Object>} Resolves promise with `{ isValid: true }` when validators passed * or with `{ isValid: false, message: '<error_message>'`} when one of the validators failed. The `message` property * contains the value that the failed validator function rejected with. */ function runValidatorFunctions(validatorFunctions, value, formState) { return Promise .all(validatorFunctions.map(validator => validator.call(null, value, formState))) // All validators passed .then(() => ({ isValid: true })) // When one of the validators failed a failure status with error message are emitted .catch(errorMessage => ({ isValid: false, message: errorMessage })); } /** * */ class AsyncValidatorRunner { /** * * @param {Rx.Scheduler} [scheduler] Optional scheduler to be used for the Rx methods that can accept one. */ constructor(scheduler) { // Rx.Scheduler to be used to run the operations on this.scheduler = scheduler; // Rx.Subject that will serve as the validator pipeline // The Runner passes the fields and values and emits // success this.validatorPipeline = new Subject(); // The amount of time to be used for debouncing the field values this.debounceTimeInMs = 400; } /** * Run the `asyncValidators` passed for the field with `fieldName`. `fieldName` is only * used to pass through to the result so `listenToValidatorsFor` can identify which field * the result belong to. * * @param {string} fieldName The name of the field * @param {Array<Function>} asyncValidators An array of functions that each return a Promise thar resolves on valid * and rejects on failure. * @param {*} value The value that should be checked for validity. * * @returns {AsyncValidatorObject} Returns itself for chaining purposes */ run(fieldName, asyncValidators = [], value) { this.validatorPipeline.next({ fieldName, asyncValidators, value }); return this; } /** * Returns an Rx.Observable that can be subscribed to to be updated of validation results for the field * with `fieldName`. This function when subscribing runs the validators that are passed for the given field when * `run` was called. This allows for only running the validators that are at the time the validation request was * issued were applicable to the field. * * @param {string} fieldName The name of the field to filter statuses for. * @returns {Rx.Observable} Observable that represents validation results for the given `fieldName`. */ listenToValidatorsFor(fieldName, formState) { return this.validatorPipeline // Filter the values by fieldName to make sure we only deal with the values for the requested field .filter(field => field.fieldName === fieldName) // Only process the latest value within the specified time window .debounceTime(this.debounceTimeInMs, this.scheduler) // .do((v) => console.log(v.value)) .map(field => Observable.fromPromise(runValidatorFunctions(field.asyncValidators, field.value, formState)) .map(status => Object.assign(status, { fieldName: field.fieldName, value: field.value }))) // Flatten all observables in the correct order they should be processed .concatAll(); // .do((v) => console.log(v)); } /** * Creates an instance of the AsyncValidatorRunner class * * @param {Rx.Scheduler} scheduler A scheduler to be used while running the pipeline operations * @returns {AsyncValidatorRunner} The instantiated runner * @static */ static create(scheduler) { return new AsyncValidatorRunner(scheduler); } } export default AsyncValidatorRunner;