webentwicklung-frage-antwort-db.com.de

Übergeben Sie das Bild von FileReader, um die Eingabe in zu übernehmen Angular 6

Ich versuche, eine Benutzeroberfläche zu erstellen, in der ein Formular mit ein paar Textfeldern, einem input type="file" und einer div vorhanden ist, die Sie mit dem Rest des Formulars zum Hochladen ablegen können. 

Mein Ziel/Logik

verwenden Sie dieselbe div, um ein Bild entweder zu löschen oder darauf zu klicken und den Ordner-Explorer zu öffnen, wie das Verhalten von input type="file". Das Aktivieren des Klickens ist in kleinen Bildschirmen sinnvoll, auf denen das Ziehen und Ablegen praktisch unmöglich ist. Und da es bereits einen input type="file" im Formular gibt, gibt es keinen Grund, das Bild aus der div zu nehmen und an das Formular usw. anzuhängen. Ich versuche das Bild, das in der div abgelegt wird, zu nehmen. , setzen Sie es als Wert in input type="file" und senden Sie das Formular einmal ab. (Wenn der Benutzer auf div geklickt hat, hat input type="file" bereits einen Wert, daher kann ich das Formular erneut senden.).

Hier ist der Code

  <div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop>
  </div> 
  <input type="file" formControlName="imageInput" required #imageInput id="imageInput" (change)='imageChange($event)' > <!-- use css to hide it -->

Wenn Sie also auf imageDrop klicken, rufen Sie tatsächlich imageChange über (click)='imageInput.click()' auf.

Dies ist das TypeScript in der Komponente.

//imageUpload is the name of the reactive form
acceptedImageTypes = {'image/png': true,'image/jpeg': true,'image/gif': true};
@ViewChild('imageDrop') imageDrop; 

allowDrop(e) {
    e.preventDefault();
  }

  drop(e) {
    e.preventDefault();  
     //clear in case we selected something before via click
    this.imageUpload.controls.imageInput.reset();  
    this.imageDrop.innerHTML="";    
    this.checkfiles(e.dataTransfer.files);
  }

  imageChange(event){    
    this.imageDrop.innerHTML="";   
    this.checkfiles(event.target.files);    
  }//imageChange

  checkfiles(files){      
    if (this.acceptedImageTypes[files[0].type] !== true){
      this.imageDrop.nativeElement.innerHTML="Not an image";          
      return;   
    }
    else if (files.length>1){
      this.imageDrop.nativeElement.innerHTML="Only one image/time";           
      return;   
    }    
    else { this.readfiles(files); }
  }//checkfiles

  readfiles(files){
    const reader = new FileReader();
    let image = new Image();
    reader.onload =  (event) =>{
      this.imageDrop.nativeElement.innerHTML="";                
      let fileReader = event.target as FileReader;
      image.src = fileReader.result;
      image.width = 150; 
      this.imageDrop.nativeElement.appendChild(image);      
    };
    reader.readAsDataURL(files[0]);    

    if (this.imageUpload.controls.imageInput.value==null) {
        //if its null then means that we dragging an img, so the previous image from the input file is deleted
        //now we got to put this image to the input file in order to submit the form
      this.imageUpload.controls.imageInput.reset(files[0] );            
    }    
  }//readfiles

  imageUploadSubmitted(){
    //when form submit, for now just check image value to check if its the right one
    console.log('IMAGE VALUE SUBMIT = =  ',this.imageUpload.controls.imageInput.value);
  }

Fehler

Wenn ich versuche, ein Bild per Drag/Drop zu ziehen, erhalte ich diesen ERROR DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string, der auf diese HTML-Zeile <div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop> verweist 

if (this.imageUpload.controls.imageInput.value==null) {
  this.imageUpload.controls.imageInput.reset(files[0] );            
} 

teil der readfiles Funktion.

Irgendwelche Ideen, wie man dieses Problem beheben kann, damit die Dateieingabe einen Wert erhält und dann das Formular abschicken kann? 

Vielen Dank

5
codebot

Okay, die Zeile, die Ihnen den Fehler gab, war this.imageUpload.controls.imageInput.setValue(files[0]);

Der Grund ist, dass der Browser Sie aufgrund von Sicherheitsproblemen daran hindert, die Datei programmgesteuert so einzustellen.

Stattdessen können Sie den e.dataTransfer.files direkt verwenden:

let input = this.imageUpload.controls.imageInput as any;
input.files = files;  

Hier ist eine Gabel deines Stackblitz

7
user184994

Was Sie zu erreichen versuchen, kann auf diese Weise nicht erreicht werden (Ursache für das, was alle Leute gesagt haben, Sicherheitsgründe usw.). 

Um zu erreichen, was Sie tun möchten, erstellen Sie mit einer Angular Lösung eine benutzerdefinierte Komponente, die mit [(ngModel)] formControlName arbeitet, indem Sie den ControlValueAccessor implementieren.

Auf diese Weise können Sie den gewünschten Wert in FormControl eingeben.

Die Implementierung von ControlValueAccessor ist Bestandteil vieler Tutorials: https://blog.angularindepth.com/never-again-be-confused-wenn-implementing-controlvalueaccessor-in-angular-forms-93b9eee9ee83

Hier finden Sie einen eigenen Code, einen Bildwähler, der in einem Formular arbeitet: 

https://github.com/xrobert35/asi-ngtools/blob/master/src/components/asi-image-chooser/asi-image-chooser.component.ts

beispiel: https://ng-tools.asi.fr/views/showroom/asi-ngtools/components/asi-image-chooser

1
xrobert35