2017-02-26 5 views
0

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.

enter image description here

Aber dieses Bild Uploader ist in einem Registerbereich.

enter image description here

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.

Antwort

1

Die Antwort war, dass ich den Validator wurde die Lösung, wenn nichts changed-

resolve();

ich die Asynchron-Validator dachte sollte, egal was gelöst werden. Aber das scheint nicht der Fall zu sein. Durch das Entfernen dieser leeren Lösung wurde das Problem behoben.

Verwandte Themen