Reputation:
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>
Upvotes: 8
Views: 74669
Reputation: 989
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)
);
Upvotes: 1
Reputation: 9
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);
}
}
Upvotes: 0
Reputation: 1052
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
}
Upvotes: 13
Reputation: 97
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>
Upvotes: 1
Reputation:
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>
Upvotes: 5
Reputation: 30088
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.
Upvotes: 6