• angular validator and async validator


    Angular Form Validation

    • 在 form.js 中参考这个方法,validator/asyncValidator 都被封装了一层。把多个 validator 方法合并成一个,然后通过forkjoin,将多个异步合并成一个,这个地方有个坑,asyncValidator 返回的虽然是AsyncValidatorFn|AsyncValidatorFn[],但是它是假设这个函数返回的是 Promise/Observable,Promise 比较简单,Observable 则必须是 compeleted 状态。jorkjoin 相当于 Promise.all(), 如果你的 Observables, 是来自于一个 Subject(Rxjs),记住一定要把它变成 completed 状态。如何变,可以采用 pipe(take(1)), 或者直接 subject.complete(), 否则,asyncValidator 不会拿到 errors. 切记切记。
    export declare interface AsyncValidatorFn {
      (control: AbstractControl):
        | Promise<ValidationErrors | null>
        | Observable<ValidationErrors | null>;
    }
    

    下面的函数该怎么看呢,首先是 setUpControl, 它会将 validator/asyncValidator 封装,可以递归方法下去,方法都在下面清单里面。
    当我们的 formControl 的值更新了,那么会首先调用 updateValueAndValidity(),

    • 这个方法里面先取消之前未完成的异步,this._cancelExistingSubscription();,
    • 然后执行同步的 validaiton, this._runValidator(),这个里面的this.validator 就是static compose(validators)的返回值,this就是 control
    • 然后计算 validaiton status, 只有同步的 validation 通过了,或者 status===PENDING,才会进行异步的 validaiton 验证。节省资源。
    if (this.status === VALID || this.status === PENDING) {
      this._runAsyncValidator(opts.emitEvent);
    }
    
    function setUpControl(control, dir) {
      //xxx 省略若干
      control.validator = Validators.compose([
        /** @type {?} */ (control.validator),
        dir.validator,
      ]);
      control.asyncValidator = Validators.composeAsync([
        /** @type {?} */ (control.asyncValidator),
        dir.asyncValidator,
      ]);
      //xxx 省略若干
    }
    
    static compose(validators) {
            if (!validators)
                return null;
            /** @type {?} */
            const presentValidators = (/** @type {?} */ (validators.filter(isPresent)));
            if (presentValidators.length == 0)
                return null;
            return (/**
             * @param {?} control
             * @return {?}
             */
            function (control) {
                return _mergeErrors(_executeValidators(control, presentValidators));
            });
        }
    static composeAsync(validators) {
            if (!validators)
                return null;
            /** @type {?} */
            const presentValidators = (/** @type {?} */ (validators.filter(isPresent)));
            if (presentValidators.length == 0)
                return null;
            return (/**
             * @param {?} control
             * @return {?}
             */
            function (control) {
                /** @type {?} */
                const observables = _executeAsyncValidators(control, presentValidators).map(toObservable);
                return forkJoin(observables).pipe(map(_mergeErrors));
            });
        }
    
    /**
     * @param {?} control
     * @param {?} validators
     * @return {?}
     */
    function _executeValidators(control, validators) {
        return validators.map((/**
         * @param {?} v
         * @return {?}
         */
        v => v(control)));
    }
    /**
     * @param {?} control
     * @param {?} validators
     * @return {?}
     */
    function _executeAsyncValidators(control, validators) {
        return validators.map((/**
         * @param {?} v
         * @return {?}
         */
        v => v(control)));
    }
    
    /**
     * @param {?} arrayOfErrors
     * @return {?}
     */
    function _mergeErrors(arrayOfErrors) {
        /** @type {?} */
        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((/**
         * @param {?} errors
         * @return {?}
         */
        (errors) => {
            res = errors != null ? Object.assign(Object.assign({}, (/** @type {?} */ (res))), errors) : (/** @type {?} */ (res));
        }));
        return Object.keys(res).length === 0 ? null : res;
    }
    
     _runValidator() {
            return this.validator ? this.validator(this) : null;
        }
        /**
         * @private
         * @param {?=} emitEvent
         * @return {?}
         */
        _runAsyncValidator(emitEvent) {
            if (this.asyncValidator) {
                ((/** @type {?} */ (this))).status = PENDING;
                /** @type {?} */
                const obs = toObservable(this.asyncValidator(this));
                this._asyncValidationSubscription =
                    obs.subscribe((/**
                     * @param {?} errors
                     * @return {?}
                     */
                    (errors) => this.setErrors(errors, { emitEvent })));
            }
        }
        /**
         * @private
         * @return {?}
         */
        _cancelExistingSubscription() {
            if (this._asyncValidationSubscription) {
                this._asyncValidationSubscription.unsubscribe();
            }
        }
    
    setErrors(errors, opts = {}) {
            ((/** @type {?} */ (this))).errors = errors;
            this._updateControlsErrors(opts.emitEvent !== false);
        }
    
    updateValueAndValidity(opts = {}) {
            this._setInitialStatus();
            this._updateValue();
            if (this.enabled) {
                this._cancelExistingSubscription();
                ((/** @type {?} */ (this))).errors = this._runValidator();
                ((/** @type {?} */ (this))).status = this._calculateStatus();
                if (this.status === VALID || this.status === PENDING) {
                    this._runAsyncValidator(opts.emitEvent);
                }
            }
            if (opts.emitEvent !== false) {
                ((/** @type {?} */ (this.valueChanges))).emit(this.value);
                ((/** @type {?} */ (this.statusChanges))).emit(this.status);
            }
            if (this._parent && !opts.onlySelf) {
                this._parent.updateValueAndValidity(opts);
            }
        }
    
  • 相关阅读:
    [安装程序配置服务器失败]解决SQL Server2000安装失败
    C# 操作 XML 增 删 改 查
    批量修改文件的编码格式
    获取SqlServer2005表结构(字段,主键,外键,递增,描述)
    .NET 特性Attribute[一]
    windows2003远程桌面退出后系统自动注销的解决方法
    SqlServer 无日志文件附加
    接受来自服务器的数据连接时发生超时(30000 毫秒)问题原因及解决方法
    .net中数据集合导出为Excel(支持泛型及显示字段顺序,可自定义显示列名)
    EF中自编写SQL脚本查询结果(适用于复杂SQL逻辑提高查询效率)
  • 原文地址:https://www.cnblogs.com/kongshu-612/p/15167418.html
Copyright © 2020-2023  润新知