2017-02-26 48 views
0

我有一個自定義圖像上傳驗證程序。這個驗證器確保mime類型是正確的,檢查文件大小,並且維度是正確的。這個驗證器的一部分創建一個圖像元素,並給它datauri(作爲src)來檢查寬度/高度。由於最後一次檢查,它使用img.onload事件,因此,這是一個異步驗證程序導致「表達已更改」的異步驗證器錯誤

我的驗證將接受的URL以及數據URI。

這裏是我的驗證的來源。我創建了一個FileValidator基類,用於檢查mimeType和文件大小,而ImageValidator檢查維度。

驗證類如下。 我做了這些類,因爲它們需要給定ValidationRules的狀態。該驗證方法是演員

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

如果標籤之間我騎車我得到這個錯誤 -

Error: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.

簡單地說,我的標籤式區域的標記是 -

<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> 

這LINE-

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

導致錯誤。但我不明白爲什麼。我認爲這與我使用異步驗證器的事實有關。

如果我註釋掉所有resolve電話在我的異步驗證器,它工作正常(但顯然我的驗證停止工作)。

所以從我所知,改變了活動頁面重新申請驗證。異步驗證器在檢查有效性後更新有效性。而對於某些原因這是一個角度問題,就像它不考慮異步任務會異步更新狀態一樣。

有沒有人知道這可能是什麼。抱歉,我無法提供簡化的工作示例,我的系統非常複雜。

EDIT

此外,如果用於輸入的值被設置僅發生。如果我在控件上調用reset或將值設置爲null(在驗證器中),則在循環制表符時不會發生這種情況。

回答

1

答案是,我是解決驗證時,沒有更改─

resolve();

我想通了異步驗證應該不管什麼解決。但似乎並非如此。刪除這個空的解決方案解決了這個問題。