异步验证器导致"表达已发生变化"错误

时间:2017-02-26 05:16:00

标签: angularjs validation angular asynchronous

我有自定义图片上传验证程序。此验证器确保mime类型正确,检查文件大小,并确保尺寸正确。此验证器的一部分创建一个图像元素,并为其提供datauri(作为src)来检查宽度/高度。由于上次检查,它使用img.onload事件,因此,这是一个异步验证器

我的验证员将接受网址和数据uris。

以下是我的验证人的来源。我创建了一个FileValidator基类,用于检查mimeType和文件大小,ImageValidator检查维度。

验证类如下。 我创建了这些类,因为它们需要给出ValidationRules的状态。验证器方法是actor

FileValidator

export class FileValidator {
  constructor(protected _rules: FileValidationRules) {}

  public validator(control: FormControl): Promise<any> {
    return new Promise((resolve, reject) => {
      var value = control.value;

      if (value) {
        if (this.isDataUri(value)) {
          if (this._rules.acceptedMimeTypes && this._rules.acceptedMimeTypes.length) {
            var mimeType = this.getMimeType(value);
            var allowedMimeType = false;

            for (var i = 0; i < this._rules.acceptedMimeTypes.length; i++) {
              if (this._rules.acceptedMimeTypes[i] === mimeType) {
                allowedMimeType = true;
                break;
              }
            }

            if (!allowedMimeType) {
              resolve({
                fileValidator: `File type not allowed: ${mimeType}. Allowed Types: ${this._rules.acceptedMimeTypes}`
              });
            }

            if (this._rules.maxSize) {
              var blob = this.dataURItoBlob(value);
              blob.size > this._rules.maxSize;

              resolve({
                fileValidator: `File is too large. File Size: ${this.getFriendlyFileSize(blob.size)}, Max Size: ${this.getFriendlyFileSize(this._rules.maxSize)}`
              });
            }
          }
        } else if (!this.isUrl(value)) {
          resolve({
            fileValidator: 'Unknown format'
          });
        }
      }

      resolve();
    });
  }

  ... Helper Methods

}

ImageValidator

export class ImageValidator extends FileValidator {

  constructor(_rules: ImageValidationRules) {
    super(_rules);
  }

  public validator(control: FormControl): Promise<any> {
    return new Promise((resolve, reject) => {
      super.validator(control).then((results) => {
        if (results && results.fileValidator) {
          resolve({
            imageValidator: results.fileValidator
          });
        }

        var value = control.value;

        if (value) {
          var rules = <ImageValidationRules>this._rules;
          if (this.isDataUri(value)) {

            if (rules.width || rules.height) {

              var img: HTMLImageElement = document.createElement('img');
              img.onload = () => {
                var validSize = true;

                if (rules.width && img.width !== rules.width) {
                  validSize = false;
                }

                if (rules.height && img.height !== rules.height) {
                  validSize = false;
                }

                if (!validSize) {
                  resolve({
                    imageValidator: `Image must be ${rules.width || 'any'}x${rules.height || 'any'}. Actual Size: ${img.width}x${img.height}` 
                  });
                }
              };
              img.src = value;

            }
          }
        }

        resolve();
      });
    });
  }

}

这一切都有效。如果我选择的图像不符合要求,我会得到正确的错误信息。

enter image description here

但是这个图片上传器位于标签区域。

enter image description here

如果我在标签之间循环,我会收到此错误 -

  

错误:检查后表达式已更改。以前的价值:&#39; true&#39;。当前价值:&#39; false&#39;。

简单地说,我的选项卡区域标记是 -

    <li *ngFor="let page of pages"
        [ngClass]="{active: page === activePage}">
      <a (click)="setActivatePage(page)">
        <i *ngIf="getFormGroup(page).invalid" class="fa fa-exclamation-circle font-red"></i>
        {{page.title}}
      </a>
    </li>

我的标签内容(简称) -

<element *ngFor="let input of activePage.inputs"
         ... etc>
</element>

这一行 -

<i *ngIf="getFormGroup(page).invalid" class="fa fa-exclamation-circle font-red"></i>

导致错误。但我无法弄清楚原因。我认为这与我使用异步验证器这一事实有关。

如果我在我的异步验证器中注释掉所有resolve个调用,它运行正常(但显然我的验证停止了)。

因此,根据我可以收集的内容,更改活动页面会重新应用验证程序。并且异步验证器在检查有效性后更新有效性。并且对于某种原因这对于角度来说是一个问题,就像它没有考虑异步任务将异步更新状态。

有谁知道这可能是什么。对不起,我无法提供简化的工作示例,我的系统很复杂。

修改

此外,仅在设置了输入值时才会出现。如果我在控件上调用reset或将值设置为null(在验证器中),则在循环选项卡时不会发生这种情况。

1 个答案:

答案 0 :(得分:1)

答案是,当没有任何改变时我正在解析验证器 -

resolve();

我认为无论如何都应该解决异步验证器。但事实似乎并非如此。删除此空解决方案可以解决问题。