Ich habe einen benutzerdefinierten Bild-Upload-Validator. Dieser Validator stellt sicher, dass der Mime-Typ korrekt ist, überprüft die Dateigröße und dass die Dimensionen korrekt sind. Ein Teil dieses Validators erzeugt ein Bildelement und gibt ihm die Dateneinheit (als src), um die Breite/Höhe zu prüfen. Aufgrund dieser letzten Überprüfung verwendet es das Ereignis img.onload
, und somit ist dies ein Async-Validator.Async-Validatoren verursachen "Ausdruck hat sich geändert" Fehler
Mein Validator wird sowohl URLs als auch Daten akzeptieren.
Hier ist die Quelle meiner Validatoren. Ich habe eine Basisklasse FileValidator
erstellt, die MimeType und Dateigröße überprüft, während die ImageValidator
Dimensionen überprüft.
Die Validierungsklassen sind wie folgt. Ich habe diese Klassen erstellt, weil sie den Status ValidationRules erfordern. Der Validator Methode ist der Schauspieler
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();
});
});
}
}
Dies alles funktioniert. Wenn ich ein Bild auswähle, das die Anforderungen nicht erfüllt, erhalte ich die entsprechende Fehlermeldung.
Aber dieses Bild Uploader ist in einem Registerbereich.
Wenn zwischen den Tabs I Zyklus ich das fehler- Markup
Error: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
Einfach gesagt, meine Tabbed Bereich is-
<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>
Und mein tabbed Inhalt ist (einfach) erhalten -
<element *ngFor="let input of activePage.inputs"
... etc>
</element>
Diese Leitungsausgangs-
<i *ngIf="getFormGroup(page).invalid" class="fa fa-exclamation-circle font-red"></i>
verursacht den Fehler. Aber ich kann nicht herausfinden warum. Ich denke, es hat etwas damit zu tun, dass ich Async-Validatoren verwende.
Wenn ich alle Anrufe resolve
in meinen Async-Validatoren auskommentiere, funktioniert es gut (aber offensichtlich funktioniert meine Validierung nicht mehr).
Also von was ich sammeln kann, Änderungen der aktiven Seite gilt Validatoren. Und die Async-Validatoren aktualisieren die Gültigkeit, nachdem die Gültigkeit überprüft wurde. Und für einige Grund ist dies ein Problem für eckig, wie es asynchrone Aufgaben nicht berücksichtigt wird Zustand asynchron.
Hat jemand eine Idee, was das sein könnte. Leider konnte ich kein vereinfachtes Arbeitsbeispiel bereitstellen, mein System ist komplex.
EDIT
Zusätzlich kommt es nur dann, wenn der Wert für den Eingang gesetzt ist. Wenn ich das Steuerelement zurücksetze oder den Wert auf Null (im Validator) setze, tritt dies beim Wechseln der Registerkarten nicht auf.