'Angular 8 - Upload file along with form and send to server
I have a reactive form in Angular 8. On form submission, I need to post the values along with the uploaded file to an API. But I am not quite sure of how to post the file along with values.
<form [formGroup]="detailsForm" (ngSubmit)="onSubmit()">
<div>
<label for="desc">Description</label>
<input type="text" id="desc" formControlName="desc"/>
</div>
<div>
<label for="summary">Summary</label>
<textarea id="summary" formControlName="summary"></textarea>
</div>
<div formGroupName="contact">
<div>
<label for="name">Name</label>
<input type="text" id="name" required formControlName="name"/>
</div>
<div>
<label for="email">Email</label>
<input type="email" id="email" formControlName="email"/>
</div>
</div>
<div>
<label for="file">Upload File</label>
<input type="file" id="file" formControlName="file">
</div>
<button type="submit">Submit</button>
</form>
In component
constructor(public httpService: HttpRequestService) { }
onSubmit() {
this.httpService.postData(this.detailsForm.value).then(
(result) => {
this.jsonResponse = result;
},
(err) => {
this.errorResponse = 'Sorry, there was an error processing your request!';
}
)
}
In service
postData(detailsData) {
const headers = new HttpHeaders(
{ 'Content-Type': 'multipart/form-data' }
);
return new Promise((resolve, reject) =>{
this.http.post('http://localhost:3000/postData', detailsData, { headers: headers })
.subscribe(res => resolve(res), err => reject(err))
});
}
In backend, just for testing purpose
const express = require("express");
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
app.use(cors());
// Configuring body parser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.listen(3000, () => {
console.log("Server running on port 3000");
});
app.post("/postData", (req,res) => {
console.log(req.body);
});
All the values are logged, but for file I am only getting the path value. How do I get the contents of file(I need to upload and send Excel File).
Solution 1:[1]
Here's what I normally do when I want to send a file to the backend.
Html element
<div class="form-group">
<input style="color:transparent;" onchange="this.style.color = 'black';" type="file"
(change)="onImageChange($event)" #bannerPhoto />
</div>
component.ts
onImageChange(event) {
const reader = new FileReader();
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
reader.readAsDataURL(file);
reader.onload = () => {
this.addEventForm.patchValue({
banner: reader.result
});
this.formData.append('banner', event.target.files[0], event.target.files[0].name);
};
}}
Here's the type of formData
and addEventForm
variables:
addEventForm: FormGroup;
formData: FormData;
How I'm calling the API:
this.eventService.add(this.formData)
.subscribe(/*Your code goes here*/)
Solution 2:[2]
I recommend you to use Multer at the backend side, and create form data request because you have a one file at the request, this condition makes the request a little bit more difficult.
You can check the npm package from: Multer NPM
The next code was extracted and adapted from the page linked before:
const cpUpload = upload.fields([
{ name: 'excel_file', maxCount: 1 },
{ name: 'description', maxCount: 1 },
{ name: 'summary', maxCount: 1 },
{ name: 'name', maxCount: 1 },
{ name: 'email', maxCount: 1 }
])
app.post('/postData', cpUpload, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['excel_file'][0] -> File
// req.files['excel_file'] -> Array but contains only 1 file
//
// req.body will contain the text fields, if there were any
const file = req.files['excel_file'][0];
const description = req.body.description;
...
})
On the client side, you first need to catch the file selected by the user:
@HostListener('change', ['$event.target.files'])
emitFiles( event: FileList ) {
const file = event && event.item(0);
if (file) {
this.file = file; // this is a variable in the component
}
}
The next step is to create the applicative FormGroup -> FormData, you can do the task by:
submit() {
const formData = new FormData();
formData.append("excel_file", this.file); // be careful, the names appended as a key in the form data must be the same of the defined fields at the backend.
formData.append("description", this.detailsForm.get("description").value;
// ... more appends from formGroup
// time to send the request!
this.httpClient.post(".../postData", formData).subscribe({
next: okResponseFromServer => {
// do anything
},
error: err => {
// handle the error
}
})
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Adrian Yama Yama |