UNPKG

forms-reactive

Version:

Reactive Form Web Component

1,538 lines (1,498 loc) 120 kB
function isFunction(x) { return typeof x === 'function'; } let _enable_super_gross_mode_that_will_cause_bad_things = false; const config = { Promise: undefined, set useDeprecatedSynchronousErrorHandling(value) { if (value) { const error = new Error(); console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n' + error.stack); } else if (_enable_super_gross_mode_that_will_cause_bad_things) { console.log('RxJS: Back to a better error behavior. Thank you. <3'); } _enable_super_gross_mode_that_will_cause_bad_things = value; }, get useDeprecatedSynchronousErrorHandling() { return _enable_super_gross_mode_that_will_cause_bad_things; }, }; function hostReportError(err) { setTimeout(() => { throw err; }, 0); } const empty = { closed: true, next(value) { }, error(err) { if (config.useDeprecatedSynchronousErrorHandling) { throw err; } else { hostReportError(err); } }, complete() { } }; const isArray = (() => Array.isArray || ((x) => x && typeof x.length === 'number'))(); function isObject(x) { return x !== null && typeof x === 'object'; } const UnsubscriptionErrorImpl = (() => { function UnsubscriptionErrorImpl(errors) { Error.call(this); this.message = errors ? `${errors.length} errors occurred during unsubscription: ${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\n ')}` : ''; this.name = 'UnsubscriptionError'; this.errors = errors; return this; } UnsubscriptionErrorImpl.prototype = Object.create(Error.prototype); return UnsubscriptionErrorImpl; })(); const UnsubscriptionError = UnsubscriptionErrorImpl; class Subscription { constructor(unsubscribe) { this.closed = false; this._parentOrParents = null; this._subscriptions = null; if (unsubscribe) { this._ctorUnsubscribe = true; this._unsubscribe = unsubscribe; } } unsubscribe() { let errors; if (this.closed) { return; } let { _parentOrParents, _ctorUnsubscribe, _unsubscribe, _subscriptions } = this; this.closed = true; this._parentOrParents = null; this._subscriptions = null; if (_parentOrParents instanceof Subscription) { _parentOrParents.remove(this); } else if (_parentOrParents !== null) { for (let index = 0; index < _parentOrParents.length; ++index) { const parent = _parentOrParents[index]; parent.remove(this); } } if (isFunction(_unsubscribe)) { if (_ctorUnsubscribe) { this._unsubscribe = undefined; } try { _unsubscribe.call(this); } catch (e) { errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e]; } } if (isArray(_subscriptions)) { let index = -1; let len = _subscriptions.length; while (++index < len) { const sub = _subscriptions[index]; if (isObject(sub)) { try { sub.unsubscribe(); } catch (e) { errors = errors || []; if (e instanceof UnsubscriptionError) { errors = errors.concat(flattenUnsubscriptionErrors(e.errors)); } else { errors.push(e); } } } } } if (errors) { throw new UnsubscriptionError(errors); } } add(teardown) { let subscription = teardown; if (!teardown) { return Subscription.EMPTY; } switch (typeof teardown) { case 'function': subscription = new Subscription(teardown); case 'object': if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') { return subscription; } else if (this.closed) { subscription.unsubscribe(); return subscription; } else if (!(subscription instanceof Subscription)) { const tmp = subscription; subscription = new Subscription(); subscription._subscriptions = [tmp]; } break; default: { throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); } } let { _parentOrParents } = subscription; if (_parentOrParents === null) { subscription._parentOrParents = this; } else if (_parentOrParents instanceof Subscription) { if (_parentOrParents === this) { return subscription; } subscription._parentOrParents = [_parentOrParents, this]; } else if (_parentOrParents.indexOf(this) === -1) { _parentOrParents.push(this); } else { return subscription; } const subscriptions = this._subscriptions; if (subscriptions === null) { this._subscriptions = [subscription]; } else { subscriptions.push(subscription); } return subscription; } remove(subscription) { const subscriptions = this._subscriptions; if (subscriptions) { const subscriptionIndex = subscriptions.indexOf(subscription); if (subscriptionIndex !== -1) { subscriptions.splice(subscriptionIndex, 1); } } } } Subscription.EMPTY = (function (empty) { empty.closed = true; return empty; }(new Subscription())); function flattenUnsubscriptionErrors(errors) { return errors.reduce((errs, err) => errs.concat((err instanceof UnsubscriptionError) ? err.errors : err), []); } const rxSubscriber = (() => typeof Symbol === 'function' ? Symbol('rxSubscriber') : '@@rxSubscriber_' + Math.random())(); class Subscriber extends Subscription { constructor(destinationOrNext, error, complete) { super(); this.syncErrorValue = null; this.syncErrorThrown = false; this.syncErrorThrowable = false; this.isStopped = false; switch (arguments.length) { case 0: this.destination = empty; break; case 1: if (!destinationOrNext) { this.destination = empty; break; } if (typeof destinationOrNext === 'object') { if (destinationOrNext instanceof Subscriber) { this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; this.destination = destinationOrNext; destinationOrNext.add(this); } else { this.syncErrorThrowable = true; this.destination = new SafeSubscriber(this, destinationOrNext); } break; } default: this.syncErrorThrowable = true; this.destination = new SafeSubscriber(this, destinationOrNext, error, complete); break; } } [rxSubscriber]() { return this; } static create(next, error, complete) { const subscriber = new Subscriber(next, error, complete); subscriber.syncErrorThrowable = false; return subscriber; } next(value) { if (!this.isStopped) { this._next(value); } } error(err) { if (!this.isStopped) { this.isStopped = true; this._error(err); } } complete() { if (!this.isStopped) { this.isStopped = true; this._complete(); } } unsubscribe() { if (this.closed) { return; } this.isStopped = true; super.unsubscribe(); } _next(value) { this.destination.next(value); } _error(err) { this.destination.error(err); this.unsubscribe(); } _complete() { this.destination.complete(); this.unsubscribe(); } _unsubscribeAndRecycle() { const { _parentOrParents } = this; this._parentOrParents = null; this.unsubscribe(); this.closed = false; this.isStopped = false; this._parentOrParents = _parentOrParents; return this; } } class SafeSubscriber extends Subscriber { constructor(_parentSubscriber, observerOrNext, error, complete) { super(); this._parentSubscriber = _parentSubscriber; let next; let context = this; if (isFunction(observerOrNext)) { next = observerOrNext; } else if (observerOrNext) { next = observerOrNext.next; error = observerOrNext.error; complete = observerOrNext.complete; if (observerOrNext !== empty) { context = Object.create(observerOrNext); if (isFunction(context.unsubscribe)) { this.add(context.unsubscribe.bind(context)); } context.unsubscribe = this.unsubscribe.bind(this); } } this._context = context; this._next = next; this._error = error; this._complete = complete; } next(value) { if (!this.isStopped && this._next) { const { _parentSubscriber } = this; if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { this.__tryOrUnsub(this._next, value); } else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { this.unsubscribe(); } } } error(err) { if (!this.isStopped) { const { _parentSubscriber } = this; const { useDeprecatedSynchronousErrorHandling } = config; if (this._error) { if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { this.__tryOrUnsub(this._error, err); this.unsubscribe(); } else { this.__tryOrSetError(_parentSubscriber, this._error, err); this.unsubscribe(); } } else if (!_parentSubscriber.syncErrorThrowable) { this.unsubscribe(); if (useDeprecatedSynchronousErrorHandling) { throw err; } hostReportError(err); } else { if (useDeprecatedSynchronousErrorHandling) { _parentSubscriber.syncErrorValue = err; _parentSubscriber.syncErrorThrown = true; } else { hostReportError(err); } this.unsubscribe(); } } } complete() { if (!this.isStopped) { const { _parentSubscriber } = this; if (this._complete) { const wrappedComplete = () => this._complete.call(this._context); if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { this.__tryOrUnsub(wrappedComplete); this.unsubscribe(); } else { this.__tryOrSetError(_parentSubscriber, wrappedComplete); this.unsubscribe(); } } else { this.unsubscribe(); } } } __tryOrUnsub(fn, value) { try { fn.call(this._context, value); } catch (err) { this.unsubscribe(); if (config.useDeprecatedSynchronousErrorHandling) { throw err; } else { hostReportError(err); } } } __tryOrSetError(parent, fn, value) { if (!config.useDeprecatedSynchronousErrorHandling) { throw new Error('bad call'); } try { fn.call(this._context, value); } catch (err) { if (config.useDeprecatedSynchronousErrorHandling) { parent.syncErrorValue = err; parent.syncErrorThrown = true; return true; } else { hostReportError(err); return true; } } return false; } _unsubscribe() { const { _parentSubscriber } = this; this._context = null; this._parentSubscriber = null; _parentSubscriber.unsubscribe(); } } function canReportError(observer) { while (observer) { const { closed, destination, isStopped } = observer; if (closed || isStopped) { return false; } else if (destination && destination instanceof Subscriber) { observer = destination; } else { observer = null; } } return true; } function toSubscriber(nextOrObserver, error, complete) { if (nextOrObserver) { if (nextOrObserver instanceof Subscriber) { return nextOrObserver; } if (nextOrObserver[rxSubscriber]) { return nextOrObserver[rxSubscriber](); } } if (!nextOrObserver && !error && !complete) { return new Subscriber(empty); } return new Subscriber(nextOrObserver, error, complete); } const observable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')(); function identity(x) { return x; } function pipeFromArray(fns) { if (fns.length === 0) { return identity; } if (fns.length === 1) { return fns[0]; } return function piped(input) { return fns.reduce((prev, fn) => fn(prev), input); }; } class Observable { constructor(subscribe) { this._isScalar = false; if (subscribe) { this._subscribe = subscribe; } } lift(operator) { const observable = new Observable(); observable.source = this; observable.operator = operator; return observable; } subscribe(observerOrNext, error, complete) { const { operator } = this; const sink = toSubscriber(observerOrNext, error, complete); if (operator) { sink.add(operator.call(sink, this.source)); } else { sink.add(this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? this._subscribe(sink) : this._trySubscribe(sink)); } if (config.useDeprecatedSynchronousErrorHandling) { if (sink.syncErrorThrowable) { sink.syncErrorThrowable = false; if (sink.syncErrorThrown) { throw sink.syncErrorValue; } } } return sink; } _trySubscribe(sink) { try { return this._subscribe(sink); } catch (err) { if (config.useDeprecatedSynchronousErrorHandling) { sink.syncErrorThrown = true; sink.syncErrorValue = err; } if (canReportError(sink)) { sink.error(err); } else { console.warn(err); } } } forEach(next, promiseCtor) { promiseCtor = getPromiseCtor(promiseCtor); return new promiseCtor((resolve, reject) => { let subscription; subscription = this.subscribe((value) => { try { next(value); } catch (err) { reject(err); if (subscription) { subscription.unsubscribe(); } } }, reject, resolve); }); } _subscribe(subscriber) { const { source } = this; return source && source.subscribe(subscriber); } [observable]() { return this; } pipe(...operations) { if (operations.length === 0) { return this; } return pipeFromArray(operations)(this); } toPromise(promiseCtor) { promiseCtor = getPromiseCtor(promiseCtor); return new promiseCtor((resolve, reject) => { let value; this.subscribe((x) => value = x, (err) => reject(err), () => resolve(value)); }); } } Observable.create = (subscribe) => { return new Observable(subscribe); }; function getPromiseCtor(promiseCtor) { if (!promiseCtor) { promiseCtor = config.Promise || Promise; } if (!promiseCtor) { throw new Error('no Promise impl found'); } return promiseCtor; } const ObjectUnsubscribedErrorImpl = (() => { function ObjectUnsubscribedErrorImpl() { Error.call(this); this.message = 'object unsubscribed'; this.name = 'ObjectUnsubscribedError'; return this; } ObjectUnsubscribedErrorImpl.prototype = Object.create(Error.prototype); return ObjectUnsubscribedErrorImpl; })(); const ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl; class SubjectSubscription extends Subscription { constructor(subject, subscriber) { super(); this.subject = subject; this.subscriber = subscriber; this.closed = false; } unsubscribe() { if (this.closed) { return; } this.closed = true; const subject = this.subject; const observers = subject.observers; this.subject = null; if (!observers || observers.length === 0 || subject.isStopped || subject.closed) { return; } const subscriberIndex = observers.indexOf(this.subscriber); if (subscriberIndex !== -1) { observers.splice(subscriberIndex, 1); } } } class SubjectSubscriber extends Subscriber { constructor(destination) { super(destination); this.destination = destination; } } class Subject extends Observable { constructor() { super(); this.observers = []; this.closed = false; this.isStopped = false; this.hasError = false; this.thrownError = null; } [rxSubscriber]() { return new SubjectSubscriber(this); } lift(operator) { const subject = new AnonymousSubject(this, this); subject.operator = operator; return subject; } next(value) { if (this.closed) { throw new ObjectUnsubscribedError(); } if (!this.isStopped) { const { observers } = this; const len = observers.length; const copy = observers.slice(); for (let i = 0; i < len; i++) { copy[i].next(value); } } } error(err) { if (this.closed) { throw new ObjectUnsubscribedError(); } this.hasError = true; this.thrownError = err; this.isStopped = true; const { observers } = this; const len = observers.length; const copy = observers.slice(); for (let i = 0; i < len; i++) { copy[i].error(err); } this.observers.length = 0; } complete() { if (this.closed) { throw new ObjectUnsubscribedError(); } this.isStopped = true; const { observers } = this; const len = observers.length; const copy = observers.slice(); for (let i = 0; i < len; i++) { copy[i].complete(); } this.observers.length = 0; } unsubscribe() { this.isStopped = true; this.closed = true; this.observers = null; } _trySubscribe(subscriber) { if (this.closed) { throw new ObjectUnsubscribedError(); } else { return super._trySubscribe(subscriber); } } _subscribe(subscriber) { if (this.closed) { throw new ObjectUnsubscribedError(); } else if (this.hasError) { subscriber.error(this.thrownError); return Subscription.EMPTY; } else if (this.isStopped) { subscriber.complete(); return Subscription.EMPTY; } else { this.observers.push(subscriber); return new SubjectSubscription(this, subscriber); } } asObservable() { const observable = new Observable(); observable.source = this; return observable; } } Subject.create = (destination, source) => { return new AnonymousSubject(destination, source); }; class AnonymousSubject extends Subject { constructor(destination, source) { super(); this.destination = destination; this.source = source; } next(value) { const { destination } = this; if (destination && destination.next) { destination.next(value); } } error(err) { const { destination } = this; if (destination && destination.error) { this.destination.error(err); } } complete() { const { destination } = this; if (destination && destination.complete) { this.destination.complete(); } } _subscribe(subscriber) { const { source } = this; if (source) { return this.source.subscribe(subscriber); } else { return Subscription.EMPTY; } } } const subscribeToArray = (array) => (subscriber) => { for (let i = 0, len = array.length; i < len && !subscriber.closed; i++) { subscriber.next(array[i]); } subscriber.complete(); }; function scheduleArray(input, scheduler) { return new Observable(subscriber => { const sub = new Subscription(); let i = 0; sub.add(scheduler.schedule(function () { if (i === input.length) { subscriber.complete(); return; } subscriber.next(input[i++]); if (!subscriber.closed) { sub.add(this.schedule()); } })); return sub; }); } function map(project, thisArg) { return function mapOperation(source) { if (typeof project !== 'function') { throw new TypeError('argument is not a function. Are you looking for `mapTo()`?'); } return source.lift(new MapOperator(project, thisArg)); }; } class MapOperator { constructor(project, thisArg) { this.project = project; this.thisArg = thisArg; } call(subscriber, source) { return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg)); } } class MapSubscriber extends Subscriber { constructor(destination, project, thisArg) { super(destination); this.project = project; this.count = 0; this.thisArg = thisArg || this; } _next(value) { let result; try { result = this.project.call(this.thisArg, value, this.count++); } catch (err) { this.destination.error(err); return; } this.destination.next(result); } } const subscribeToPromise = (promise) => (subscriber) => { promise.then((value) => { if (!subscriber.closed) { subscriber.next(value); subscriber.complete(); } }, (err) => subscriber.error(err)) .then(null, hostReportError); return subscriber; }; function getSymbolIterator() { if (typeof Symbol !== 'function' || !Symbol.iterator) { return '@@iterator'; } return Symbol.iterator; } const iterator = getSymbolIterator(); const subscribeToIterable = (iterable) => (subscriber) => { const iterator$1 = iterable[iterator](); do { let item; try { item = iterator$1.next(); } catch (err) { subscriber.error(err); return subscriber; } if (item.done) { subscriber.complete(); break; } subscriber.next(item.value); if (subscriber.closed) { break; } } while (true); if (typeof iterator$1.return === 'function') { subscriber.add(() => { if (iterator$1.return) { iterator$1.return(); } }); } return subscriber; }; const subscribeToObservable = (obj) => (subscriber) => { const obs = obj[observable](); if (typeof obs.subscribe !== 'function') { throw new TypeError('Provided object does not correctly implement Symbol.observable'); } else { return obs.subscribe(subscriber); } }; const isArrayLike = ((x) => x && typeof x.length === 'number' && typeof x !== 'function'); function isPromise(value) { return !!value && typeof value.subscribe !== 'function' && typeof value.then === 'function'; } const subscribeTo = (result) => { if (!!result && typeof result[observable] === 'function') { return subscribeToObservable(result); } else if (isArrayLike(result)) { return subscribeToArray(result); } else if (isPromise(result)) { return subscribeToPromise(result); } else if (!!result && typeof result[iterator] === 'function') { return subscribeToIterable(result); } else { const value = isObject(result) ? 'an invalid object' : `'${result}'`; const msg = `You provided ${value} where a stream was expected.` + ' You can provide an Observable, Promise, Array, or Iterable.'; throw new TypeError(msg); } }; function scheduleObservable(input, scheduler) { return new Observable(subscriber => { const sub = new Subscription(); sub.add(scheduler.schedule(() => { const observable$1 = input[observable](); sub.add(observable$1.subscribe({ next(value) { sub.add(scheduler.schedule(() => subscriber.next(value))); }, error(err) { sub.add(scheduler.schedule(() => subscriber.error(err))); }, complete() { sub.add(scheduler.schedule(() => subscriber.complete())); }, })); })); return sub; }); } function schedulePromise(input, scheduler) { return new Observable(subscriber => { const sub = new Subscription(); sub.add(scheduler.schedule(() => input.then(value => { sub.add(scheduler.schedule(() => { subscriber.next(value); sub.add(scheduler.schedule(() => subscriber.complete())); })); }, err => { sub.add(scheduler.schedule(() => subscriber.error(err))); }))); return sub; }); } function scheduleIterable(input, scheduler) { if (!input) { throw new Error('Iterable cannot be null'); } return new Observable(subscriber => { const sub = new Subscription(); let iterator$1; sub.add(() => { if (iterator$1 && typeof iterator$1.return === 'function') { iterator$1.return(); } }); sub.add(scheduler.schedule(() => { iterator$1 = input[iterator](); sub.add(scheduler.schedule(function () { if (subscriber.closed) { return; } let value; let done; try { const result = iterator$1.next(); value = result.value; done = result.done; } catch (err) { subscriber.error(err); return; } if (done) { subscriber.complete(); } else { subscriber.next(value); this.schedule(); } })); })); return sub; }); } function isInteropObservable(input) { return input && typeof input[observable] === 'function'; } function isIterable(input) { return input && typeof input[iterator] === 'function'; } function scheduled(input, scheduler) { if (input != null) { if (isInteropObservable(input)) { return scheduleObservable(input, scheduler); } else if (isPromise(input)) { return schedulePromise(input, scheduler); } else if (isArrayLike(input)) { return scheduleArray(input, scheduler); } else if (isIterable(input) || typeof input === 'string') { return scheduleIterable(input, scheduler); } } throw new TypeError((input !== null && typeof input || input) + ' is not observable'); } function from(input, scheduler) { if (!scheduler) { if (input instanceof Observable) { return input; } return new Observable(subscribeTo(input)); } else { return scheduled(input, scheduler); } } function forkJoin(...sources) { if (sources.length === 1) { const first = sources[0]; if (isArray(first)) { return forkJoinInternal(first, null); } if (isObject(first) && Object.getPrototypeOf(first) === Object.prototype) { const keys = Object.keys(first); return forkJoinInternal(keys.map(key => first[key]), keys); } } if (typeof sources[sources.length - 1] === 'function') { const resultSelector = sources.pop(); sources = (sources.length === 1 && isArray(sources[0])) ? sources[0] : sources; return forkJoinInternal(sources, null).pipe(map((args) => resultSelector(...args))); } return forkJoinInternal(sources, null); } function forkJoinInternal(sources, keys) { return new Observable(subscriber => { const len = sources.length; if (len === 0) { subscriber.complete(); return; } const values = new Array(len); let completed = 0; let emitted = 0; for (let i = 0; i < len; i++) { const source = from(sources[i]); let hasValue = false; subscriber.add(source.subscribe({ next: value => { if (!hasValue) { hasValue = true; emitted++; } values[i] = value; }, error: err => subscriber.error(err), complete: () => { completed++; if (completed === len || !hasValue) { if (emitted === len) { subscriber.next(keys ? keys.reduce((result, key, i) => (result[key] = values[i], result), {}) : values); } subscriber.complete(); } } })); } }); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ function isEmptyInputValue(value) { // we don't check for string here so it also works with arrays return value == null || value.length === 0; } function hasValidLength(value) { // non-strict comparison is intentional, to check for both `null` and `undefined` values return value != null && typeof value.length === 'number'; } // eslint-disable-next-line max-len const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; function isPresent(o) { return o != null; } function mergeErrors(arrayOfErrors) { let res = {}; // Not using Array.reduce here due to a Chrome 80 bug // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982 arrayOfErrors.forEach((errors) => { res = errors != null ? Object.assign(Object.assign({}, res), errors) : res; }); return Object.keys(res).length === 0 ? null : res; } function executeValidators(control, validators) { return validators.map(validator => validator(control)); } function isValidatorFn(validator) { return !validator || !validator.validate; } function toObservable(r) { const obs = r instanceof Promise ? from(r) : r; if (!(obs instanceof Observable)) { throw new Error('Expected validator to return Promise or Observable.'); } return obs; } /** * @description * Provides a set of built-in validators that can be used by form controls. * * A validator is a function that processes a `FormControl` or collection of * controls and returns an error map or null. A null map means that validation has passed. * * @see [Form Validation](/guide/form-validation) * * @publicApi */ class Validators { /** * @description * Validator that requires the control's value to be greater than or equal to the provided number. * The validator exists only as a function and not as a directive. * * @usageNotes * * ### Validate against a minimum of 3 * * ```typescript * const control = new FormControl(2, Validators.min(3)); * * console.log(control.errors); // {min: {min: 3, actual: 2}} * ``` * * @returns A validator function that returns an error map with the * `min` property if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static min(min) { return (control) => { if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) { return null; // don't validate empty values to allow optional controls } const value = parseFloat(control.value); // Controls with NaN values after parsing should be treated as not having a // minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min // tslint:disable-next-line: object-literal-key-quotes return !Number.isNaN(value) && value < min ? { min: { min, actual: control.value } } : null; }; } /** * @description * Validator that requires the control's value to be less than or equal to the provided number. * The validator exists only as a function and not as a directive. * * @usageNotes * * ### Validate against a maximum of 15 * * ```typescript * const control = new FormControl(16, Validators.max(15)); * * console.log(control.errors); // {max: {max: 15, actual: 16}} * ``` * * @returns A validator function that returns an error map with the * `max` property if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static max(max) { return (control) => { if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) { return null; // don't validate empty values to allow optional controls } const value = parseFloat(control.value); // Controls with NaN values after parsing should be treated as not having a // maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max // tslint:disable-next-line: object-literal-key-quotes return !Number.isNaN(value) && value > max ? { max: { max, actual: control.value } } : null; }; } /** * @description * Validator that requires the control have a non-empty value. * * @usageNotes * * ### Validate that the field is non-empty * * ```typescript * const control = new FormControl('', Validators.required); * * console.log(control.errors); // {required: true} * ``` * * @returns An error map with the `required` property * if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static required(control) { // tslint:disable-next-line: object-literal-key-quotes return isEmptyInputValue(control.value) ? { required: true } : null; } /** * @description * Validator that requires the control's value be true. This validator is commonly * used for required checkboxes. *F * @usageNotes * * ### Validate that the field value is true * * ```typescript * const control = new FormControl('', Validators.requiredTrue); * * console.log(control.errors); // {required: true} * ``` * * @returns An error map that contains the `required` property * set to `true` if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static requiredTrue(control) { // tslint:disable-next-line: object-literal-key-quotes return control.value === true ? null : { required: true }; } /** * @description * Validator that requires the control's value pass an email validation test. * * Tests the value using a [regular * expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) * pattern suitable for common usecases. The pattern is based on the definition of a valid email * address in the [WHATWG HTML * specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with * some enhancements to incorporate more RFC rules (such as rules related to domain names and the * lengths of different parts of the address). * * The differences from the WHATWG version include: * - Disallow `local-part` (the part before the `@` symbol) to begin or end with a period (`.`). * - Disallow `local-part` to be longer than 64 characters. * - Disallow the whole address to be longer than 254 characters. * * If this pattern does not satisfy your business needs, you can use `Validators.pattern()` to * validate the value against a different pattern. * * @usageNotes * * ### Validate that the field matches a valid email pattern * * ```typescript * const control = new FormControl('bad@', Validators.email); * * console.log(control.errors); // {email: true} * ``` * * @returns An error map with the `email` property * if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static email(control) { if (isEmptyInputValue(control.value)) { return null; // don't validate empty values to allow optional controls } // tslint:disable-next-line: object-literal-key-quotes EMAIL_REGEXP.lastIndex = 0; return EMAIL_REGEXP.test(control.value) ? null : { email: true }; } /** * @description * Validator that requires the length of the control's value to be greater than or equal * to the provided minimum length. This validator is also provided by default if you use the * the HTML5 `minlength` attribute. Note that the `minLength` validator is intended to be used * only for types that have a numeric `length` property, such as strings or arrays. The * `minLength` validator logic is also not invoked for values when their `length` property is 0 * (for example in case of an empty string or an empty array), to support optional controls. You * can use the standard `required` validator if empty values should not be considered valid. * * @usageNotes * * ### Validate that the field has a minimum of 3 characters * * ```typescript * const control = new FormControl('ng', Validators.minLength(3)); * * console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}} * ``` * * ```html * <input minlength="5"> * ``` * * @returns A validator function that returns an error map with the * `minlength` if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static minLength(minLength) { return (control) => { if (isEmptyInputValue(control.value) || !hasValidLength(control.value)) { // don't validate empty values to allow optional controls // don't validate values without `length` property return null; } return control.value.length < minLength // tslint:disable-next-line: object-literal-key-quotes ? { minlength: { requiredLength: minLength, actualLength: control.value.length } } : null; }; } /** * @description * Validator that requires the length of the control's value to be less than or equal * to the provided maximum length. This validator is also provided by default if you use the * the HTML5 `maxlength` attribute. Note that the `maxLength` validator is intended to be used * only for types that have a numeric `length` property, such as strings or arrays. * * @usageNotes * * ### Validate that the field has maximum of 5 characters * * ```typescript * const control = new FormControl('Angular', Validators.maxLength(5)); * * console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}} * ``` * * ```html * <input maxlength="5"> * ``` * * @returns A validator function that returns an error map with the * `maxlength` property if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static maxLength(maxLength) { return (control) => (hasValidLength(control.value) && control.value.length > maxLength // tslint:disable-next-line: object-literal-key-quotes ? { maxlength: { requiredLength: maxLength, actualLength: control.value.length } } : null); } /** * @description * Validator that requires the control's value to match a regex pattern. This validator is also * provided by default if you use the HTML5 `pattern` attribute. * * @usageNotes * * ### Validate that the field only contains letters or spaces * * ```typescript * const control = new FormControl('1', Validators.pattern('[a-zA-Z ]*')); * * console.log(control.errors); // {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'}} * ``` * * ```html * <input pattern="[a-zA-Z ]*"> * ``` * * @param pattern A regular expression to be used as is to test the values, or a string. * If a string is passed, the `^` character is prepended and the `$` character is * appended to the provided string (if not already present), and the resulting regular * expression is used to test the values. * * @returns A validator function that returns an error map with the * `pattern` property if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static pattern(pattern) { if (!pattern) { return Validators.nullValidator; } let regex; let regexStr; if (typeof pattern === 'string') { regexStr = ''; if (pattern.charAt(0) !== '^') regexStr += '^'; regexStr += pattern; if (pattern.charAt(pattern.length - 1) !== '$') regexStr += '$'; regex = new RegExp(regexStr); } else { regexStr = pattern.toString(); regex = pattern; } return (control) => { if (isEmptyInputValue(control.value)) { return null; // don't validate empty values to allow optional controls } const { value } = control; regex.lastIndex = 0; // Reset regex!! return regex.test(value) ? null : { pattern: { requiredPattern: regexStr, actualValue: value } }; }; } /** * @description * Validator that performs no operation. * * @see `updateValueAndValidity()` * */ static nullValidator(_control) { return null; } static compose(validators) { if (!validators) return null; const presentValidators = validators.filter(isPresent); if (presentValidators.length === 0) return null; return function (control) { return mergeErrors(executeValidators(control, presentValidators)); }; } /** * @description * Compose multiple async validators into a single function that returns the union * of the individual error objects for the provided control. * * @returns A validator function that returns an error map with the * merged error objects of the async validators if the validation check fails, otherwise `null`. * * @see `updateValueAndValidity()` * */ static composeAsync(validators) { if (!validators) return null; const presentValidators = validators.filter(isPresent); if (presentValidators.length === 0) return null; return (control) => { const observables = executeValidators(control, presentValidators).map(toObservable); return forkJoin(observables).pipe(map(mergeErrors)); }; } } /** * Given a validator that may be a function or a class, return the * validator function (convert validator classes into validator functions). * * @param validators The validator that may be a plain function * as well as represented as a validator class. */ function normalizeValidator(validator) { return isValidatorFn(validator) ? validator : ((c) => validator.validate(c)); } /** * Given the list of validators that may contain both functions as well as classes, return the list * of validator functions (convert validator classes into validator functions). This is needed to * have consistent structure in validators list before composing them. * * @param validators The set of validators that may contain validators both in plain function form * as well as represented as a validator class. */ function normalizeValidators(validators) { return validators.map(validator => normalizeValidator(validator)); } /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ // tslint:disable-next-line: prefer-array-literal function composeValidators(validators) { return validators != null ? Validators.compose(normalizeValidators(validators)) : null; } // tslint:disable-next-line: prefer-array-literal function composeAsyncValidators(validators) { return validators != null ? Validators.composeAsync(normalizeValidators(validators)) : null; } var ReactiveFormStatus; (function (ReactiveFormStatus) { /** * Reports that a FormControl is valid, meaning that no errors exist in the input value. * * @see `status` */ ReactiveFormStatus["VALID"] = "VALID"; /** * Reports that a FormControl is invalid, meaning that an error exists in the input value. * * @see `status` */ ReactiveFormStatus["INVALID"] = "INVALID"; /** * Reports that a FormControl is pending, meaning that that async validation is occurring and * errors are not yet available for the input value. * * @see `markAsPending` * @see `status` */ ReactiveFormStatus["PENDING"] = "PENDING"; /** * Reports that a FormControl is disabled, meaning that the control is exempt from ancestor * calculations of validity or value. * * @see `markAsDisabled` * @see `status` */ ReactiveFormStatus["DISABLED"] = "DISABLED"; })(ReactiveFormStatus || (ReactiveFormStatus = {})); /* eslint-disable @typescript-eslint/no-use-before-define */ /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ function _find(control, path, delimiter) { let mPath = path; if (mPath == null) { return null; } if (!Array.isArray(mPath)) { mPath = mPath.split(delimiter); } if (Array.isArray(mPath) && mPath.length === 0) ret