prerequisite: this tutorial require you already a basic understanding of server-side application and nodejs.
There are so many modules you can use to upload files to the server, but I will be using express-fileupload. and my client application is angular and the server is nodejs.
1. Installation
You can visit the link to learn more about express-fileupload. However, the following command will install express-fileupload.
npm install express-fileupload
Next, is my client's (angular material step form) view where I will upload company details along with five documents.
The HTML code below the preview screenshot above.
<mat-horizontal-stepper [linear]="isLinear" #stepper>
<mat-step >
<!-- contact details -->
<form #contactForm="ngForm" name="contactForm" class="form" >
<ng-template matStepLabel>contacts</ng-template>
<mat-form-field>
<mat-label>ComPany name</mat-label>
<input matInput readonly #companyName placeholder="company name" type="text"
name="companyName" [(ngModel)]="companyModel.companyName" required>
</mat-form-field>
<mat-form-field>
<mat-label>ComPany Address</mat-label>
<input matInput #companyAddress placeholder="company address" type="text"
name="companyAddress" [(ngModel)]="companyModel.companyAddress" required>
</mat-form-field>
<mat-form-field>
<mat-label>ComPany Phome</mat-label>
<input matInput #companyPhone placeholder="company phone" type="text"
name="companyPhone" [(ngModel)]="companyModel.companyPhone" required>
</mat-form-field>
<mat-form-field>
<mat-label>Contact mail</mat-label>
<input matInput #contactMail placeholder="company mail" type="email"
name="contactMail" [(ngModel)]="companyModel.contactMail" required>
</mat-form-field>
<div>
<button color="primary" [disabled]="!contactForm.valid" mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step >
<!-- company cac certificate -->
<form #detailForm="ngForm" name="detailForm" class="form" >
<ng-template matStepLabel>details</ng-template>
<mat-form-field>
<mat-label>Rc numbers</mat-label>
<input matInput #rcNumber placeholder="registration number" type="text"
name="rcNumber" [(ngModel)]="companyModel.rcNumber" required>
</mat-form-field>
<ion-row>
<ion-col>
<small class="ion-margin">cac certificate</small>
<ion-item >
<ion-input #cacCertificate type="file" (change)="cacCertInput($event)"
name="cacCertificate" accept=".pdf" [(ngModel)]="companyModel.cacCertificate" required></ion-input>
</ion-item>
</ion-col>
</ion-row>
<mat-form-field>
<mat-label>cac status</mat-label>
<input matInput #cacCertStatus placeholder=" approved" type="text"
name="cacCertStatus" [(ngModel)]="companyModel.cacCertStatus" required>
</mat-form-field>
<div>
<button color="warn" mat-button matStepperPrevious>Back</button>
<button color="primary" [disabled]="!detailForm.valid" mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step >
<!-- award form -->
<form #awardForm="ngForm" name="awardForm" class="form" >
<ng-template matStepLabel>award</ng-template>
<ion-row>
<ion-col>
<small class="ion-margin">award letter</small>
<ion-item >
<ion-input #awardLatter type="file" (change)="awardLatterInput($event)"
name="awardLatter" accept=".pdf" [(ngModel)]="companyModel.awardLetter" required></ion-input>
</ion-item>
</ion-col>
</ion-row>
<mat-form-field>
<mat-label>award leter status</mat-label>
<input matInput #cacCertStatus placeholder="approved" type="text"
name="awardLetterStatus" [(ngModel)]="companyModel.awardLetterStatus" required>
</mat-form-field>
<div>
<button color="warn" mat-button matStepperPrevious>Back</button>
<button color="primary" [disabled]="!awardForm.valid" mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step >
<!-- contract form -->
<form #contractForm="ngForm" name="contractForm" class="form" >
<ng-template matStepLabel>contract</ng-template>
<mat-form-field>
<mat-label>number of contract</mat-label>
<input matInput #numberOfContracts placeholder="" type="text"
name="numberOfContracts" [(ngModel)]="companyModel.numberOfContract" required>
</mat-form-field>
<ion-row>
<ion-col>
<small class="ion-margin">contract latter</small>
<ion-item >
<ion-input #contractLatter type="file" (change)="contractLatterInput($event)"
name="contractLatter" accept=".pdf" [(ngModel)]="companyModel.contractLetter" required></ion-input>
</ion-item>
</ion-col>
</ion-row>
<mat-form-field>
<mat-label>contract later status</mat-label>
<input matInput #contractLatterStatus placeholder="" type="text"
name="contractLatterStatus" [(ngModel)]="companyModel.contractLetterStatus" required>
</mat-form-field>
<div>
<button color="warn" mat-button matStepperPrevious>Back</button>
<button color="primary" [disabled]="!contractForm.valid" mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step >
<!-- tax form -->
<form #taxForm="ngForm" name="taxForm" class="form" >
<ng-template matStepLabel>tax</ng-template>
<ion-row>
<ion-col>
<small class="ion-margin">tax clearance</small>
<ion-item >
<ion-input #taxClearance type="file" (change)="taxClearanceInput($event)"
name="taxClearance" accept=".pdf" [(ngModel)]="companyModel.taxClearance" required></ion-input>
</ion-item>
</ion-col>
</ion-row>
<mat-form-field>
<mat-label>tax document status</mat-label>
<input matInput #taxClearanceStatus placeholder="" type="text"
name="taxClearanceStatus" [(ngModel)]="companyModel.taxClearanceStatus" required>
</mat-form-field>
<div>
<button color="warn" mat-button matStepperPrevious>Back</button>
<button color="primary" [disabled]="!taxForm.valid" mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step >
<!-- mou -->
<form #mouForm="ngForm" name="mouForm" class="form" >
<ng-template matStepLabel>mou</ng-template>
<ion-row>
<ion-col>
<small class="ion-margin">mou document</small>
<ion-item >
<ion-input #mouFile type="file" (change)="mouFileInput($event)"
name="mouFile" accept=".pdf" [(ngModel)]="companyModel.mouFile"
required></ion-input>
required></ion-input>
</ion-item>
</ion-col>
</ion-row>
<mat-form-field>
<mat-label>mou document status</mat-label>
<input matInput #mouFileStatus placeholder="approved" type="text"
name="mouFileStatus" [(ngModel)]="companyModel.mouFileStatus" required>
</mat-form-field>
<div>
<button color="warn" mat-button matStepperPrevious>Back</button>
<button color="primary" [disabled]="!mouForm.valid" mat-button
matStepperNext>Next</button>
matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step >
<!-- position -->
<form #positionForm="ngForm" name="positionForm" class="form" >
<ng-template matStepLabel>position</ng-template>
<mat-form-field>
<mat-label>your position</mat-label>
<input matInput #yourPosition placeholder="" type="text"
name="yourPosition" [(ngModel)]="companyModel.yourPosition" required>
</mat-form-field>
<mat-form-field>
<mat-label>your name</mat-label>
<input matInput #yourName placeholder="" type="text"
name="yourName" [(ngModel)]="companyModel.yourName" required>
</mat-form-field>
<ion-col>
<mat-form-field>
<mat-label>director 1</mat-label>
<input matInput #director1 placeholder="" type="text"
name="director1" [(ngModel)]="companyModel.director1" required>
</mat-form-field>
<mat-form-field>
<mat-label>director 1 phone</mat-label>
<input matInput #director1Phone placeholder="" type="text"
name="director1Phone" [(ngModel)]="companyModel.director1Phone" required>
</mat-form-field>
</ion-col>
<ion-col>
<mat-form-field>
<mat-label>director 2</mat-label>
<input matInput #director2 placeholder="" type="text"
name="director2" [(ngModel)]="companyModel.director2" required>
</mat-form-field>
<mat-form-field>
<mat-label>director 2 phone</mat-label>
<input matInput #director2Phone placeholder="" type="text"
name="director2Phone" [(ngModel)]="companyModel.director2Phone" required>
</mat-form-field>
</ion-col>
<div>
<button color="warn" mat-button matStepperPrevious>Back</button>
<ion-button color="success" [disabled]="!positionForm.valid"
(click)="submitRecord()">finish</ion-button>
(click)="submitRecord()">finish</ion-button>
</div>
</form>
</mat-step>
</mat-horizontal-stepper>
the above form is binded to the following form
companyModel = { companyName:'', rcNumber:'', companyAddress:'',
companyPhone:'',contactMail:'', numberOfContract:'',cacCertificate:null,
cacCertStatus:'', awardLetter:null, awardLetterStatus:'', contractLetter:null,
contractLetterStatus:'', mouFile:null, mouFileStatus:'', taxClearance:null,
taxClearanceStatus:'', yourPosition:'', yourName:'',director1:'', director2:'',
director1Phone:'', director2Phone:''
}
Next, after filling our form, on submission we will pass the model values to formData() below
submitRecord(){
console.log(this.companyModel);
const formData = new FormData();
formData.append('companyName', this.companyModel.companyName);
formData.append('rcNumber', this.companyModel.rcNumber);
formData.append('companyAddress', this.companyModel.companyAddress);
formData.append('companyPhone', this.companyModel.companyPhone);
formData.append('contactMail', this.companyModel.contactMail);
formData.append('numberOfContract', this.companyModel.numberOfContract);
formData.append('cacCertificate', this.companyModel.cacCertificate, this.companyModel.cacCertificate.name);
formData.append('cacCertStatus', this.companyModel.cacCertStatus);
formData.append('awardLetter', this.companyModel.awardLetter, this.companyModel.awardLetter.name);
formData.append('awardLetterStatus', this.companyModel.awardLetterStatus);
formData.append('contractLetter', this.companyModel.contractLetter, this.companyModel.contractLetter.name);
formData.append('contractLetterStatus', this.companyModel.contractLetterStatus);
formData.append('mouFile', this.companyModel.mouFile, this.companyModel.mouFile.name);
formData.append('mouFileStatus', this.companyModel.mouFileStatus);
formData.append('taxClearance', this.companyModel.taxClearance, this.companyModel.taxClearance.name);
formData.append('taxClearanceStatus', this.companyModel.taxClearanceStatus);
formData.append('yourPosition', this.companyModel.yourPosition);
formData.append('yourName', this.companyModel.yourName);
formData.append('director1', this.companyModel.director1);
formData.append('director2', this.companyModel.director2);
formData.append('director1Phone', this.companyModel.director1Phone);
formData.append('director2Phone', this.companyModel.director2Phone);
this.companyService.submitCompanyRecord(formData).subscribe(
res => {
console.log(res);
this.userService.generalToastShort('success', res['msg']);
this.clearForm();
setTimeout(()=> {
this.router.navigateByUrl('/my-company');
})
},
err => {
console.log(err);
this.userService.generalToast('error', err.error.msg);
}
);
}
the following is an API to submit the formdata housing our files and documents.
submitCompanyRecord(comRecord){
return this.http.post(environment.apiBaseUrl + '/company/submit-record', comRecord);
}
Next is where is an API endpoint which will save our document. As expected you should have created a general folder for the incoming files and a model for JSON object.
The first thing to do is to import all the necessary modules.
const express = require("express");
const mongoose = require('mongoose');
const router = express.Router();
const fs = require('fs');
const path = require('path');
const jwt_helper = require('../config/jwt_helper');
const CompanyModel = mongoose.model('companyModel');
Next, I will check if the incoming request has incoming else I will send and error messages with a status code of 400.
router.post('/submit-record',jwt_helper.verifyJwtToken, async (req, res)=>{
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send({msg:'No files were uploaded.'});
}else{
if everything is ok, I want to remove white space from the company's name and create a folder with that folder name with space.
const company_folder = req.body.companyName.toLowerCase().split(' ').join('_');
console.log('com folder',company_folder);
try{
// crete company's folder
await fs.promises.mkdir(`data/${company_folder}`, { recursive: true })
} catch(err){
console.log(err, 'ERROR CREATING COMPANY FOLDER');
}
Next, we will save all necessary body object using companyModel instance.
var newCompanyRecord = new CompanyModel();
newCompanyRecord.user_id = req._id;
newCompanyRecord.companyName = req.body.companyName;
newCompanyRecord.rcNumber = req.body.rcNumber;
newCompanyRecord.companyAddress = req.body.companyAddress;
newCompanyRecord.companyPhone = req.body.companyPhone;
newCompanyRecord.contactMail = req.body.contactMail;
newCompanyRecord.numberOfContract = req.body.numberOfContract;
// cac certificate
newCompanyRecord.cacCertificate.name = req.files.cacCertificate.name;
newCompanyRecord.cacCertificate.status = req.body.cacCertStatus;
newCompanyRecord.cacCertificate.url = `data/${company_folder}/`+req.files.cacCertificate.name;
// award letter
newCompanyRecord.awardLetter.name = req.files.awardLetter.name;
newCompanyRecord.awardLetter.status = req.body.awardLetterStatus;
newCompanyRecord.awardLetter.url = `data/${company_folder}/`+req.files.awardLetter.name;
// award letter
newCompanyRecord.contractLetter.name = req.files.contractLetter.name;
newCompanyRecord.contractLetter.status = req.body.contractLetterStatus;
newCompanyRecord.contractLetter.url = `data/${company_folder}/`+req.files.contractLetter.name;
// mou letter
newCompanyRecord.mouFile.name = req.files.mouFile.name;
newCompanyRecord.mouFile.status = req.body.mouFileStatus;
newCompanyRecord.mouFile.url = `data/${company_folder}/`+req.files.mouFile.name;
// taxClearance letter
newCompanyRecord.taxClearance.name = req.files.taxClearance.name;
newCompanyRecord.taxClearance.status = req.body.taxClearanceStatus;
newCompanyRecord.taxClearance.url = `data/${company_folder}/`+req.files.taxClearance.name;
newCompanyRecord.yourPosition = req.body.yourPosition;
newCompanyRecord.yourName = req.body.yourName;
console.log('contact mail',req.body.contactMail);
newCompanyRecord.contactEmail = req.body.contactEmail;
newCompanyRecord.director1.name = req.body.director1;
newCompanyRecord.director1.phone = req.body.director1Phone;
newCompanyRecord.director2.name = req.body.director2;
newCompanyRecord.director2.phone = req.body.director2Phone;
newCompanyRecord.save().then((record)=> {
console.log(record);
res.status(200).send({msg:' record has been saved!'});
})
}
} );
router.get('/get-company', jwt_helper.verifyJwtToken, async (req, res)=> {
await CompanyModel.find({user_id: req._id}).then((record)=> {
if(!record){
res.status(404).send({msg:'no record found'});
}else{
res.status(200).send({record: record});
}
});
if your upload process successful, you will get a success response at the client-side and your metadata saved in database and files saved in a folder. data/company name.
So this is you can upload multiple file/ form object using express-fileupload.
0 Comments