Передайте изображение из FileReader для формирования ввода в Angular 6 - PullRequest
0 голосов
/ 15 сентября 2018

Я пытаюсь создать пользовательский интерфейс, в котором есть форма с парой текстовых полей, input type="file" и div, в которую вы можете перетаскивать изображения для загрузки вместе с остальной частью формы.

Моя цель / логика

использовать тот же div, чтобы либо перетащить изображение, либо щелкнуть по нему и открыть проводник папок, как input type="file".Включение нажатия имеет смысл на маленьких экранах, где практически невозможно «перетащить».И поскольку в форме уже есть input type="file", нет смысла извлекать изображение из div, добавлять его к форме и т. Д. И т. Д. Я пытаюсь взять изображение, которое было сброшено вэто значение в input type="file" и отправьте форму один раз.(если пользователь нажал на div, то input type="file" уже имеет значение, поэтому я снова могу отправить форму снова).

Вот код

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

Таким образом, при нажатии imageDrop фактически вызывается imageChange через (click)='imageInput.click()'

Это машинопись в компоненте.

//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);
  }

Ошибки

Когда я пытаюсь перетащить изображение, я получаю 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, указывающее на эту строку HTML <div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop>, но я уверен, что оно связано с

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

часть функции readfiles.

Есть идеи, как это исправить, чтобы при вводе файла можно было получить значение и потом было свободно отправлять форму?

Спасибо

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

То, что вы пытаетесь сделать, не может быть достигнуто таким образом (причина того, что сказал каждый человек, причина безопасности и т. Д ...).

Чтобы добиться того, что вы хотите сделать, угловое решение должно создать пользовательский компонент, работающий с [(ngModel)] formControlName, путем реализации ControlValueAccessor .

Сделав это, вы сможете поместить в FormControl все, что захотите в качестве значения.

Реализация ControlValueAccessor является частью многих учебников: https://blog.angularindepth.com/never-again-be-confused-when-implementing-controlvalueaccessor-in-angular-forms-93b9eee9ee83

Здесь вы можете найти собственный код для выбора изображений, работающий в форме:

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

пример: https://ng -tools.asi.fr / views / showroom / asi-ngtools / components / asi-image-chooser

0 голосов
/ 15 сентября 2018

Хорошо, строка с сообщением об ошибке была this.imageUpload.controls.imageInput.setValue(files[0]);

Причина в том, что браузер не позволит программно настроить файл таким образом из-за проблем с безопасностью.

Вместо этого вы можете использовать e.dataTransfer.files напрямую:

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

Вот ответвление вашего стекаблита

...