10

I am trying to build a form in Angular 6 that offers a file selection box that allows the user to select multiple files (Stackblitz: https://stackblitz.com/edit/angular-yjummp).

The Template looks like:

<form [formGroup]="form">
    <input id="files" formControlName="files" type="file" accept="image/*,video/*" multiple (change)="onFilesChanged($event)"/>
</form>

I am building the form in TypeScript like this:

  public form = new FormGroup({
    files: new FormControl('')
  });

  public onFilesChanged(event: any): void {
    console.log(event.target.files);
    console.log(this.form.value);
  }

Now, in the onFilesChanged Handler, the selected files can be correctly retrieved from the event by accessing event.target.files (obviously), but printing the form value only prints one file. I have been trying a number of ways using FormArray as well, but had no luck so far.

Any ideas? Many thanks!

2
  • 1
    Tomorrow I publish the answer, now I have to sleep after breaking my head solving this. Commented Nov 13, 2018 at 5:30
  • 1
    @nicogaldo: any chance you could share your solution with us? Commented Dec 4, 2018 at 12:11

1 Answer 1

16

Below is example that how I achieved multiple photo upload input file through angular reactive forms.

public demoForm: FormGroup;

constructor(private formBuilder: FormBuilder) { 
    this.demoForm = this.formBuilder.group({
       text_input: ['', Validators.required],
       photos: this.formBuilder.array([])
    });
}

// We will create multiple form controls inside defined form controls photos.
createItem(data): FormGroup {
    return this.formBuilder.group(data);
}

//Help to get all photos controls as form array.
get photos(): FormArray {
    return this.demoForm.get('photos') as FormArray;
};

detectFiles(event) {
    let files = event.target.files;
    if (files) {
        for (let file of files) {
            let reader = new FileReader();
            reader.onload = (e: any) => {
                this.photos.push(this.createItem({
                    file,
                    url: e.target.result  //Base64 string for preview image
                }));
            }
            reader.readAsDataURL(file);
        }
    }
}

In component html

<input type="file" class="custom-file-input form-control" id="files" multiple (change)="detectFiles($event)" accept="image/x-png,image/jpeg">

<div class="images-preview mt-2" *ngIf="photos.length">
    <div formArrayName="photos" *ngFor="let photo of photos.controls; let i = index;">
        <div [formGroupName]="i">
            <img [src]="photo.controls.url.value" class="card-img-top" alt="Image Preview">
        </div>
    </div>
</div>

You can avoid html if you do not want to show preview. On submit of form you will be get values like below.

{
    text_input: "",
    photos: [
       {
           file: <File Object>,
           url: <Base64 String here>
       },
       {
           file: <File Object>,
           url: <Base64 String here>
       },
       ....
    ] 
}

Edit Here is working stackblitz example

I hope it will helps you and also other peoples. Thanks.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your answer! Unfortunately I cannot confirm that this answer is working at the moment, but I'll accept in anyways and will undo in case it's not working. Again: many thanks!
not the perfect solution! but it works in some cases
@sadeghhp Can you perhaps provide issue so I can correct it.
at backend i got file:{} instead of file: <File Object>
@suhailvs Make sure you send a correct request because of photos array that i created here to print file object and base64 both so you might need to array with only [<File Object>, <File Object>, <File Object>, ...] and that should send in multipart form data request.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.