我有一個自定義圖像上傳驗證程序。這個驗證器確保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();
});
});
}
}
這一切工作。如果我選擇的圖片不符合要求,我會收到正確的錯誤消息。
但這圖片上傳是標籤式區域。
如果標籤之間我騎車我得到這個錯誤 -
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(在驗證器中),則在循環制表符時不會發生這種情況。