Angular 7: Как мне отправить файл / изображение вместе с моей реактивной формой? - PullRequest
1 голос
/ 19 марта 2019

Я создал простую реактивную форму с вводом текста, и когда форма отправляется, я хочу передать изображение из файла ввода.Каждый раз, когда я захожу в Google, я получаю учебники, в которых показано, как я могу загрузить файл, но это делается без другого поля ввода.Я понимаю, как это сделать, что я не понимаю, как отправить обе формы вместе с вводом файла в одной отправке.

В моем сценарии я не должен использовать реактивные формы и вместо этого просто new FormData() и добавить каждый вклад в это?

Если я могу это сделать, оставьте мне простой пример.

edit: Как включить элемент управления загрузкой файлов в реактивную форму Angular2? Это не ответ.Рынок ответов там не публикует файл вместе с реактивной формой, он публикует файл один.

Ответы [ 2 ]

2 голосов
/ 19 марта 2019

Файлы представляют собой двоичные данные, поля формы обычно представляют собой текстовые файлы json. Чтобы они оба были в одном сообщении, вам нужно преобразовать одну из ваших данных в другую. Я сделал это, преобразовав файл в строку base64, а затем добавив его в обычные данные json. Очевидно, что вам нужно преобразовать строку base64 обратно в файл, но большинство сред (например, C #) могут сделать это из коробки.

Вот некоторый код, чтобы показать вам, как я это сделал:

HTML (это кнопка файла, вы должны использовать ее, чтобы ваш браузер позволял вам выбирать файл из файловой системы):

<input name="imageUrl" type="file" [accept]="filePattern" multiple=""
                                (change)="handleInputChange($event)" />

.ts:

    handleInputChange(e) {
    const file = e.dataTransfer ? e.dataTransfer.files[0] : e.target.files[0];
    const reader = new FileReader();

    const fileDto: Partial<IFileSaveDto> = {
        // your other data here
        title: 'what ever here',
        fileAsBase64: null
    };

    reader.onload = (ev: ProgressEvent) => {
        fileDto.fileAsBase64 = reader.result;
    };

    reader.readAsDataURL(file);
}

Недостаток этого подхода заключается в том, что base64 генерирует некоторые накладные расходы. Если вы загружаете очень большие или много файлов, это не очень хороший подход.

Вот полный объясненный пример: https://nehalist.io/uploading-files-in-angular2/

1 голос
/ 28 марта 2019

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

import {
  Component,
  OnInit,
  ChangeDetectorRef
} from '@angular/core';
import {
  FormGroup,
  FormBuilder,
  Validators
} from '@angular/forms';


export class TodoFormComponent {
  todoForm: FormGroup = this.fb.group({
    todo: ['', Validators.required],
    image: ['', Validators.required], //making the image required here
    done: [false]
  })

  constructor(
    private fb: FormBuilder,
    private cd: ChangeDetectorRef
  ) {}

  /**
   *@param event {EventObject} - the javascript change event
   *@param field {String} - the form field control name
   */
  onFileChange(event, field) {
    if (event.target.files && event.target.files.length) {
      const [file] = event.target.files;
      // just checking if it is an image, ignore if you want
      if (!file.type.startsWith('image')) {
        this.todoForm.get(field).setErrors({
          required: true
        });
        this.cd.markForCheck();
      } else {
        // unlike most tutorials, i am using the actual Blob/file object instead of the data-url
        this.todoForm.patchValue({
          [field]: file
        });
        // need to run CD since file load runs outside of zone
        this.cd.markForCheck();
      }
    }

    onSubmit() {
      const formData = new FormData();
      Object.entries(this.todoForm.value).forEach(
        ([key, value]: any[]) => {
          formData.set(key, value);
        }

        //submit the form using formData
        // if you are using nodejs use something like multer
      )
    }

  }
<form [formGroup]="todoForm" (ngSubmit)="onSubmit()">
  <input type="file" formControlName="image" (onchange)="onFileChange($event, 'image')"/>
  <textarea formControlName="todo"></textarea>
  <button type="submit">Submit</button>
</form>

На стороне сервера вы можете обрабатывать запрос так же, как обрабатывает запрос данных формы

...