8

I am trying to save files along with FormData in Angular 5. I can get the single file, but have no idea how to get all the files uploaded. I have three image files and input fields, tried searching examples. But only got for multiple file uploads. I want to upload each and every single file from this form.

Below is my code :

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Location } from '@angular/common';
import { ActivatedRoute } from '@angular/router';
import { Category } from '../../../shared/services/categories/category';
import { CategoriesService } from '../../../shared/services/categories/categories.service';

@Component({
  selector: 'app-add-category',
  templateUrl: './add-category.component.html',
  styleUrls: ['./add-category.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class AddCategoryComponent implements OnInit {
  
  category: Category = new Category();
  fileToUpload: File = null;
  
  constructor(
    private categoriesService: CategoriesService,
    private route: ActivatedRoute,
    private location: Location  
  ) { }

  ngOnInit() {
  }

  goBack(): void {
    this.location.back();
  }

  handleFileInput(files: FileList) {
    console.log(files);
  }

  addCategory() {
    console.log(this.category);
    this.categoriesService.createCategory(this.category).subscribe(() => this.goBack());
  }

}
          <h3 class="box-title">Category</h3>

        <form role="form" (ngSubmit)="addCategory()" #categoryForm="ngForm">

              <div class="box-body">

                <div class="row">
                  <div class="col-lg-6">
                  <label for="Category Name">Name</label>
                  <input type="text" class="form-control" [(ngModel)]="category.category_name" name="category_name" id="category_name" placeholder="Enter Category Name" required="">
                </div>

                <div class="col-lg-6">
                  <label for="Category Path">Path</label>
                  <input type="text" class="form-control" [(ngModel)]="category.category_path" name="category_path" id="category_path" required="">
                </div>
              </div>
            </div>
            <br/>

            <div class="form-group">
                  <label for="Category Description">Description</label>
                  <textarea rows="3" [(ngModel)]="category.category_description" name="category_description" id="category_description" class="form-control" required=""></textarea>
            </div>
                
            <div class="col-lg-12 text-center">
                <input type="file" [(ngModel)]="category.category_banner" (change)="handleFileInput($event.target.files)" class="custom-file-input" name="category_banner" id="category_banner">
                <label class="custom-file-label" for="customFile">Banner</label>
            </div>
            <br/>

            <div class="form-group">
              <label for="Category Banner Code">Banner Code</label>
              <textarea rows="3" [(ngModel)]="category.category_banner_code" name="category_banner_code" id="category_banner_code" class="form-control" required=""></textarea>
            </div>
            
            <br/>
            
            <div class="col-lg-12">
                <input type="file" [(ngModel)]="category.category_image" (change)="handleFileInput($event.target.files)" class="custom-file-input" name="category_image" id="category_image">
                <label class="custom-file-label" for="customFile">Image</label>
            </div>
        
            <br/>

            <div class="col-lg-12">
                <input type="file" [(ngModel)]="category.category_icon" (change)="handleFileInput($event.target.files)" class="custom-file-input" name="category_icon" id="category_icon">
                <label class="custom-file-label" for="customFile">Icon</label>
            </div>

              <div class="form-group">
              <label for="Category Meta Title">Meta Title</label>
              <input type="text" [(ngModel)]="category.category_meta_title" class="form-control" name="category_meta_title" id="category_meta_title" placeholder="Enter Meta Title" required="">
            </div>

            <div class="form-group">
              <label for="Category Meta Description">Meta Description</label>
              <input type="text" [(ngModel)]="category.category_meta_decription" class="form-control" id="category_meta_description" name="category_meta_description" placeholder="Enter Meta Description" required="">
            </div>

            <div class="form-group">
              <label for="Category Meta Keyword">Meta Keyword</label>
              <input type="text" [(ngModel)]="category.category_meta_keyword" class="form-control" id="category_meta_keyword" name="category_meta_keyword" placeholder="Enter Meta Keyword" required="">
            </div>

            <div class="form-group">
             
              <div class="row">
                 <div class="col">Featured :</div>
                <div class="col">
                <label class="radio-inline" for="Category Featured">
                  <input type="radio" [(ngModel)]="category.category_featured" name="category_featured" id="category_featured" value="1" required="">Yes
                </label>
              </div>

              <div class="col">
                <label class="radio-inline" for="Category Featured">
                  <input type="radio" [(ngModel)]="category.category_featured" name="category_featured" id="category_featured" value="0" required="">No
                </label>
            </div>
            </div>
            </div>
              
            <input type="hidden" [(ngModel)]="category.category_status" name="category_status" id="category_status" value="1">

              <div class="box-footer col-md-12">
                <button type="submit" class="btn btn-primary">Submit</button>
              </div>
            </form>

6 Answers 6

13

I recently had a similar issue. This can be solved by setting the content type of header as null in the Angular code. Attaching the code snippet of Angular5 and spring boot backend.

let headers = new HttpHeaders();
//this is the important step. You need to set content type as null
headers.set('Content-Type', null);
headers.set('Accept', "multipart/form-data");
let params = new HttpParams();
const formData: FormData = new FormData();
for (let i = 0; i < this.filesList.length; i++) {
  formData.append('fileArray', this.filesList[i], this.filesList[i].name);
} 
formData.append('param1', this.param1);
formData.append('param2', this.param2);
this.http.post(this.ROOT_URL + this.SERVICE_ENDPOINT, formData, { params, headers }).subscribe((res) => {
    console.log(res);
});

In the spring boot backend, you need to have the controller as

@RequestMapping(value = "/uploadAndSendEmail", method = RequestMethod.POST, consumes= "multipart/form-data")    
public ResponseEntity<String> uploadAndSendEmail(@RequestParam("fileArray") MultipartFile[] fileArray, 
        @RequestParam(value = "param1", required = false) String param1,
        @RequestParam(value = "param2", required = false) String param2) {
        //do your logic
        }
Sign up to request clarification or add additional context in comments.

Comments

6

Here's how I handle multiple files from a single file input. My component gathers the form data, and produces a Data object, which does not contain the files. It then calls this service method with the Data object and the files, which sends the data and the files in a multipart post.

  save(data: Data, filesForUpload: File[]): Observable<Data> {
    const formData = new FormData();

    // add the files
    if (filesForUpload && filesForUpload.length) {
      filesForUpload.forEach(file => formData.append('files', file));
    }

    // add the data object
    formData.append('data', new Blob([JSON.stringify(data)], {type: 'application/json'}));

    return this.http.post<Data>(this.apiUrl, formData);
  }

So, to handle two file inputs, you could do this:

 save(data: Data, filesA: File[], filesB: File[]): Observable<Data> {
    const formData = new FormData();

    // add the files
    if (filesA && filesA.length) {
      filesA.forEach(file => formData.append('filesA', file));
    }

    if (filesB && filesB.length) {
      filesB.forEach(file => formData.append('filesB', file));
    }

    // add the data object
    formData.append('data', new Blob([JSON.stringify(data)], {type: 'application/json'}));

    return this.http.post<Data>(this.apiUrl, formData);
  }

Which would give you three parts in your multipart post, one for each set of files, and one for the data object.

2 Comments

I am not trying to handle multiple files from a single file input. I am not clear with the filesA and filesB example I tried this : code' handleFileInput(files: FileList) { this.fileToUpload = files.item(0); }'code I have three image upload buttons and I want to send them in post along with the formData.
Single-file upload works the same as multi-file upload, it's still in an array, but there's only one item in the array. Or, you can just pass in the one item via files.item(0); In the example, I'm passing in two arrays of files assuming that there are two inputs. If there were three inputs, you'd pass three arrays (or three individual items). The reason that I'm sending them separately in the POST is so that you can know on the server side which file came from which input.
5

This is what I tried and it worked as expected :

handleCategoryBanner(files: FileList) {
    this.category.category_banner = '/categories/download/' + files[0].name;
    this.formData.append('category_banner', files[0], files[0].name);
    this.categoryContainersService.uploadFile(this.formData).subscribe(filename => console.log(files[0].name));
  }
<div class="col-lg-12 text-center">
        <input type="file" (change)="handleCategoryBanner($event.target.files)" class="custom-file-input" id="category_banner" accept=".jpeg,.png,.jpg">
        <input type="hidden" name="category_banner" [(ngModel)]="category.category_banner" />
        <label class="custom-file-label" for="customFile">Banner</label>
    </div>

Comments

1

just put 'multiple' attribute on your input tag now by selecting 2 or more files on browsing you will get object should iterate on it to extract images on it. like this-->

 <div class="form-group">
    <label for="file">Choose File</label>
    <input type="file" id="file" (change)="handleFileInput($event.target.files)" multiple>
</div>

1 Comment

it is not from the same input field for upload
1

Was having same trouble the below code worked for me

postFile(apiPath: string, data:any){
    this.http.post<any>(apiPath, data).subscribe(
      (res) => console.log(res),
      (err) => console.log(err)
    );

Comments

0

Try this code:

handleFileInput(files){
     for (let j = 0; j < files.length; j++) {
      let data = new FormData();
      let fileItem = files[j]._file;
      console.log(fileItem.name);
      data.append('file', fileItem);
    }
}

Comments

Your Answer

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