In Angular 6, after POSTing big file in Mozilla RAM usage skyrockets - javascript

I have an Angular 6 app that uploads one file using POST:
submit-form.component.html
<input type="file" id="file" (change)="onFileChange($event.target.files)">
<button (click)="uploadFile()"> Upload </button>
submit-form.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpResponse, HttpEventType } from '#angular/common/http';
import { FileService } from '../file.service';
#Component({
selector: 'app-submit-form',
templateUrl: './submit-form.component.html',
styleUrls: ['./submit-form.component.css']
})
export class SubmitFormComponent implements OnInit {
constructor( private fileService: FileService) { }
file_to_upload: File;
onFileChange(files: FileList) {
this.file_to_upload = files.item(0);
}
uploadFile() {
this.fileService.uploadFile(this.file_to_upload).subscribe(
(event) => {
if (event.type == HttpEventType.UploadProgress) {
const percentDone = Math.round(100 * event.loaded / event.total);
console.log(`Uploading - %${percentDone}...`);
} else if (event instanceof HttpResponse) {
console.log('File completely loaded!');
}
},
(err) => {
console.log('Upload Error', JSON.stringify(err));
}, () => {
console.log('Done uploading file!');
}
);
}
}
file.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpParams, HttpRequest } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class FileService {
private uploadUrl = 'http://localhost:4200/upload';
constructor(private http: HttpClient) { }
uploadFile(file: File): Observable<any> {
var formData = new FormData();
formData.append('file_to_upload', file, file.name);
var params = new HttpParams();
var httpOptions = {
params: params,
reportProgress: true
};
const req = new HttpRequest('POST', this.uploadUrl, formData, httpOptions);
return this.http.request(req);
}
}
And Node.JS server that saves that file using multer:
server.js
const http = require('http')
const url = require('url')
const path = require('path')
const multer = require('multer')
const express = require('express')
const router = express()
const serverPort = 4200;
router.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
var storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, 'data/upload/'),
filename: (req, file, cb) => {
console.log('Upload file ', file)
cb(null, file.originalname)
}
});
var upload = multer({storage: storage});
router.post('/upload', upload.single('file_to_upload'), (req, res) => {
res.json({'Code': 200, 'Message': 'Success'});
});
router.listen(serverPort, () => console.log(`Server running at http://localhost:${serverPort}/`));
On Mozilla it works perfectly with small files (<500MB), but when I upload something bigger, the browser freezes between Uploading - 100% and File completely loaded!, rapidly raises it's memory consumption by approximately 1.5x file size and then instantly drops back down, outputting File completely loaded! and Done uploading file! (judging by data/upload/ folder, the file finishes uploading somewhere at the beginning of a memory spike). On Chrome file size does not matter - it always works properly (even with >3GB files).
If I use HTML's <form> for file upload, like this:
<form action="http://localhost:4200/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file_to_upload" >
<input type="submit" value="Upload">
</form>
...then in both browsers there are no sudden memory spikes. So, what's going on?

Related

I keep getting http POST http://localhost:3000/api/authenticate 404 (Not Found)

am using angular 6 and express when am developing this api on authentcate uri it returning Http failure response for http://localhost:3000/api/authenticate: 404 Not Found
i have tried removing of the responses on my user.controller.js but the problem persisits it seems am missing out some point here and i dont know here it is at first i got an error saaying cant send headers after they are sent and the error was on my user.controller.js on this line else return res.status(404).json(info);
Here is my user.controller.js
const mongoose = require('mongoose');
const User = mongoose.model('User');
const passport = require('passport');
const _ = require('lodash');
module.exports.register = (req,res, next) => {
const user = new User();
user.fullname = req.body.fullname;
user.email = req.body.email;
user.College = req.body.College;
user.Department = req.body.Department;
user.password = req.body.password;
user.admintype = req.body.admintype;
user.save((err, doc) => {
if(!err) { res.send(doc)}
else
{
if(err.code == 11000)
res.status(422).send(['Duplicate email Address Found.'])
else
return next(err);
}
})
}
module.exports.authenticate = (req, res, next ) => {
//calll for passport authentication
passport.authenticate('local', (err, user, info) => {
//error form paasport middleware
if(err) return res.status(400).json(err);
//registered user
else if (user) return res.status(200).json({ "token":user.generateJwt() });
//unknown user or wrong password
else return res.status(404).json(info);
})(req, res);
}
module.exports.userProfile = (req, res, next) =>{
User.findOne({ _id:req._id},
(err,user) =>{
if(!user)
return res.status(404).json({ status: false, message : 'User Record not Found. '});
else
return res.status(200).json({ status:true , user : _.pick(user, ['fullname','email','university','College','Department','admintype'])});
} );
}
Here is my user.service.ts
```import { Injectable } from '#angular/core';
import { User } from './user.model';
import{ HttpClient, HttpHeaders } from '#angular/common/http';
import{ environment } from '../../environments/environment';
import { from } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class UserService {
selectedUser: User = {
fullname:'',
email:'',
university:'',
College:'',
Department:'',
password:'',
admintype:''
};
constructor(private http: HttpClient) { }
postUser(user:User)
{
return this.http.post(environment.apiBaseUrl+ '/register' ,user)
}
login(authCredentials)
{
return this.http.post(environment.apiBaseUrl+ '/authenticate',authCredentials);
}
setToken(token:string)
{
localStorage.setItem('token',token);
}
}```
Here is my sign-in.components.ts
```import { Component, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
import { UserService } from 'src/app/shared/user.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.css']
})
export class SignInComponent implements OnInit {
constructor( private userService:UserService, private router:Router) { }
model = {
email:'',
password:''
};
emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
serverErrorMessages : string;
ngOnInit() {
}
onSubmit(form :NgForm)
{
this.userService.login(form.value).subscribe(
res =>{
this.userService.setToken(res['token']);
this.router.navigateByUrl('/signup');
},
err =>{
this.serverErrorMessages = err.message;
});
}
}```
Here is my environment.ts
```/ This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false,
apiBaseUrl:'http://localhost:3000/api'
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.```
Here is my auth.js
```const router = require('express').Router();
const User = require('../controller/model/User');
const ctrlUser = require('../controller/user.controller');
const jwthelper = require('../jwtHelper')
//validation
router.post('/register', ctrlUser.register);
router.post('/authenticate',ctrlUser.authenticate);
router.get('/userProfile',jwthelper.verifyJwtToken,ctrlUser.userProfile);
module.exports = router;```
Here is my index.js
```const express = require('express');
const app = express();
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const cors = require('cors')
const bodyParser = require('body-parser');
require('./passportConfig');
const passport = require('passport');
dotenv.config();
//connect to mongodb
mongoose.set('useFindAndModify', false); mongoose.set('useUnifiedTopology', true);
mongoose.connect(process.env.DB_CONNECT,{ useNewUrlParser:true} , () =>
console.log('connected to db!')
);
//import routes
const authRoute = require('./routes/auth');
//middleware
app.use(bodyParser.json());
app.use(cors());
app.use(passport.initialize());
//error handler
app.use((err, req, res, next) =>{
if(err.name =='ValidationError')
{
var valErrs = [];
Object.keys(err.errors).forEach(key => valErrs.push(err.errors[key].message));
res.status(422).send(valErrs);
next();
}
});
//route middleware
app.use('/api',authRoute);
app.listen(3000, () => console.log("server Up and Running"));```
Any Help please on this one please thank you all
The only thing which is remain is to attach the router which you have define in the auth.js file to your express app like this
const authRouter = require('./auth');
And to prefix all routes define in the auth.js file you attach it as a middleware which is trigger on route prifix with \api
const express = require('express');
const app = express();
// define all your middleware and all other route
// and here you attach the auth router
app.use('\api', authRouter);
This will make authentication available on url http://localhost:3000/api/authenticate
You may also get 404 because of this line in authenticate route (by the way I think this must be a 400 - bad request, not 404, which is making confusion.)
else return res.status(404).json(info);
So to understand this, can you replace your authenticate route like this, and see what logs in the api console:
module.exports.authenticate = (req, res, next ) => {
console.log("req.body: ", req.body)
//calll for passport authentication
passport.authenticate('local', (err, user, info) => {
//error form paasport middleware
if(err) return res.status(400).json(err);
//registered user
else if (user) return res.status(200).json({ "token":user.generateJwt() });
//unknown user or wrong password
else {
console.log("info: ", info)
return res.status(400).json(info);
}
})(req, res);
Also it the angular component, can you change your onSubmit like this for easy debug:
be sure your form.value is correct:
onSubmit(form :NgForm)
{
console.log("form.value: ", form.value);
this.userService.login(form.value).subscribe(
res =>{
this.userService.setToken(res['token']);
this.router.navigateByUrl('/signup');
},
err =>{
console.log("err: ", err.message)
this.serverErrorMessages = err.message;
});
}

Nest.js: handle multiple file processing using multer

While developing on a 'clean' node.js frameworks, like Express.js - we can just easily handle file processing, callbacks, validations etc. But using Nest.js -> it's becoming simpler for simple issues, but more complex when you want to tune it...
I want to upload multiple files on the server, and right after that call another service action (like processing data from files async etc). Nest.js is using multer for this. And I got stuck...
import { Controller, HttpException, HttpStatus, Post, UploadedFiles, UseInterceptors } from '#nestjs/common';
import { AnyFilesInterceptor } from '#nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';
import { v4 as uuid } from 'uuid';
#Controller('reader')
export class ReaderController {
#Post('upload')
#UseInterceptors(
AnyFilesInterceptor({
storage: diskStorage({
destination: './uploads',
fileSize: 5e7,
files: 20,
filename: (req, file, cb) => {
try {
const fileName = uuid();
return cb(null, `${fileName}${extname(file.originalname)}`);
} catch (err) {
return cb(new HttpException('Errored at upload', HttpStatus.BAD_REQUEST));
}
}
}),
fileFilter: (req: any, file: any, cb: any) => {
if (file.mimetype.match(/\/(png)$/)) {
cb(null, true);
} else {
cb(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST
),
false
);
}
}
})
)
uploadFile(#UploadedFiles() files) {
console.log('files', files); // <--- here
}
}
How can I on my upload success action (or not success) handle it? How can i handle async file upload status? Like first file was uploaded with OK/NOK status and proceed with other files here (I will need to emit Socket action with 'file#n was uploaded with OK status')?
Normally I will just write something similar:
async.each(req.files, function(file, callback) {
saveFile(file, file.name, callback)
}, function(err) {
res.send('')
})

Using Angular, ExpressJS, NodeJS to download a text Document with a button

I am trying to create a download button, which enables the user to download a document from my node.js server.
Here's the fancy button:
I am using Angular as a front-end framework and node.js and express.js for the backend.
This is the document I would like the user to be able to download:
So for the backend I wrote this code:
server.js
const bodyParser = require('body-parser');
const cors = require('cors')
const express = require('express');
const app = express();
const router = express.Router();
const path = require('path');
app.use(cors());
app.use(bodyParser.json());
router.route('/generateReportByGet').get((req, res) => {
res.download(path.join(__dirname, 'docs/doc1.txt'), function (err) {
if (err) {
console.log(err);
} else {
console.log('%c%s', 'color: #f2ceb6', 'NO ERROR');
console.log('%c%s', 'color: #00a3cc', res);
}
});
});
app.use('/', router);
app.listen(5353, () => console.log('Express server running on port 5353'));
After running the server.js file, and typing:
localhost:5353/generateReportByGet
The file gets downloaded:
So here's what my logic told me:
Create a button with Angular that sends a GET request to that same
adress and I should get the same result: The file gets downloaded.
So my first question is : Is my logic flawed?
So here's the front-end code:
app.component.html:
<button color="primary" (click)="generateReportbyGet()">Generate report By Get</button>
<router-outlet></router-outlet>
app.component.ts:
import { Component } from "#angular/core";
import { GenerateReportService } from "./services/generate-report.service";
#Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
constructor(private generateReportService: GenerateReportService) {}
generateReportbyGet() {
this.generateReportService.generateReportbyGet().subscribe((results) => {
console.log("generateReportbyGet ...");
console.log('%c%s', 'color: #aa00ff', results);
}
}
generate-report.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class GenerateReportService {
uri = 'http://localhost:5353';
constructor(private http: HttpClient) {}
generateReportbyGet() {
return this.http.get(`${this.uri}/generateReportByGet`, {responseType: 'text'});
}
}
I thought this should work as I described. However, when I click on the button nothing happens.
But, on the browser console, I am able to retrieve the text from the file:
So here's my second question:
2/ Why doesn't the file downloading process get started when I click on the button? Is it a problem with the code or the GET request logic?
Thank you!!
In your Node JS server side code... you're reading the contents of the file and sending them...
(1) to return a file, you can do a:
app.get('/generateReportByGet', function (req, res) { res.sendFile(__dirname + "/" + "docs/doc1.txt"); })
(2) or you can do a (as per this):
app.get('/generateReportByGet', function(req, res){
const file = `${__dirname}/docs/doc1.txt`;
res.download(file);
});
File can't be downloaded making ajax call.
In your component service change below code.
generateReportbyGet() {
var link=document.createElement('a');
link.href=`${this.uri}/generateReportByGet`;
link.download="MyDoc.txt";
link.click();
}

React - Axios is sending file data as undefined to a Node server

I am trying to upload a single file, and store it in a folder in my app directory. On the frontend, I am successfully selecting a file and adding it to the state of the Uploader component. When I make the POST request to the Node route with Axios, I am getting undefined in the request body.
Here is the component:
import React, { Component } from 'react';
import axios from 'axios';
export default class SandboxGet extends Component {
constructor(props) {
super(props);
this.state = {
file: null
};
}
fileSelectHandler = event => {
const file = event.target.files[0];
this.setState({ file: file.name });
};
fileUploadHandler = () => {
const data = new FormData();
data.append('file', this.state.file);
console.log(data);
axios
.post('http://localhost:4000/upload/', this.state.file, {
// receive two parameter endpoint url ,form data
})
.then(res => {
// then print response status
console.log(res.statusText);
});
};
render() {
return (
<div className="uploaderContainer">
<div className="uploadInput">
<i className="fas fa-upload" />
<button className="uploadBtn">Select Files</button>
<input type="file" name="file" onChange={this.fileSelectHandler} />
<div className="fileName">{this.state.fileName}</div>
</div>
<button className="uploadFile" onClick={this.fileUploadHandler}>
Upload!
</button>
</div>
);
}
}
Here is the Node server:
const express = require('express');
const app = express();
const multer = require('multer');
const cors = require('cors');
app.use(cors());
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, '/storage');
},
filename: (req, file, cb) => {
cb(null, Date.now() + '-' + file.originalname);
}
});
const upload = multer({ storage: storage }).single('file');
app.post('/upload', (req, res) => {
console.log(req.file); // => returns nothing
console.log(req.body; // => returns nothing
upload(req, res, function(err) {
if (err instanceof multer.MulterError) {
return res.status(500).json(err);
} else if (err) {
return res.status(500).json(err);
}
return res.status(200).send(req.file);
});
});
app.listen(4000, function() {
console.log('App running on port 3000');
});
I feel like I am getting close, but I am missing a big piece of the puzzle.
You are sending the this.state.file. You need to send the FormData.
In your case it is .post('http://localhost:4000/upload/', data)
Also, you need to send the multipart/form-data header.
const headers = {
'content-type': 'multipart/form-data'
}
Then,
axios.post('http://localhost:4000/upload/', data, {headers});

how to dump csv data into mongoDB using angular and nodejs

I've a csv file and want to dump the data in it into mongodb using angular and nodejs.
Need help to read csv file's data using angular and parse it and store in mongodb
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class TemplateService {
domain = 'http://localhost:3000';
constructor(private http: Http) { }
postCsvToMongo(csvJson: any) {
console.log('CSV!!!' + csvJson);
return this.http.post(this.domain + '/fu/fileupload', csvJson).map(res => res.json());
}
}
this is the code i'm using to send json object over post routes.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>TypeError: Converting circular structure to JSON
<br> at JSON.stringify (<anonymous>)
<br> at router.post (/home/agam/projects/AMEX/routes/fileUpload.js:10:23)
<br> at Layer.handle [as handle_request] (/home/agam/projects/AMEX/node_modules/express/lib/router/layer.js:95:5)
<br> at next (/home/agam/projects/AMEX/node_modules/express/lib/router/route.js:137:13)
<br> at Route.dispatch (/home/agam/projects/AMEX/node_modules/express/lib/router/route.js:112:3)
<br> at Layer.handle [as handle_request] (/home/agam/projects/AMEX/node_modules/express/lib/router/layer.js:95:5)
<br> at /home/agam/projects/AMEX/node_modules/express/lib/router/index.js:281:22
<br> at Function.process_params (/home/agam/projects/AMEX/node_modules/express/lib/router/index.js:335:12)
<br> at next (/home/agam/projects/AMEX/node_modules/express/lib/router/index.js:275:10)
<br> at Function.handle (/home/agam/projects/AMEX/node_modules/express/lib/router/index.js:174:3)
<br> at router (/home/agam/projects/AMEX/node_modules/express/lib/router/index.js:47:12)
<br> at Layer.handle [as handle_request] (/home/agam/projects/AMEX/node_modules/express/lib/router/layer.js:95:5)
<br> at trim_prefix (/home/agam/projects/AMEX/node_modules/express/lib/router/index.js:317:13)
<br> at /home/agam/projects/AMEX/node_modules/express/lib/router/index.js:284:7
<br> at Function.process_params (/home/agam/projects/AMEX/node_modules/express/lib/router/index.js:335:12)
<br> at next (/home/agam/projects/AMEX/node_modules/express/lib/router/index.js:275:10)
</pre>
</body>
</html>
this is the error i'm getting when I'm trying to debug the request received over the post request on node side.
And how to receive the file over back end??
var csv = require('fast-csv');
var mongoose = require('mongoose');
var Bulletin = require('../models/bulletin');
var multer = require("multer");
module.exports = (router) => {
router.post('/fileupload', (req, res) => {
console.log('### ' + req);
res.send(req.files);
});
/*router.post('/fileupload', multer({dest: "./uploads/"}).array("uploads", 12), function(req, res) {
res.send(req.files);
});*/
return router;
};
This is the nodejs code
1","Fed official says weak data caused by weather, should not slow taper","http://www.latimes.com/business/money/la-fi-mo-federal-reserve-plosser-stimulus-economy-20140310,0,1312750.story\?track=rss","Los Angeles Times","b","www.latimes.com","1394470370698
2","Fed's Charles Plosser sees high bar for change in pace of tapering","http://www.livemint.com/Politics/H2EvwJSK2VE6OF7iK1g3PP/Feds-Charles-Plosser-sees-high-bar-for-change-in-pace-of-ta.html","Livemint","b","www.livemint.com","1394470371207
3","US open: Stocks fall after Fed official hints at accelerated tapering","http://www.ifamagazine.com/news/us-open-stocks-fall-after-fed-official-hints-at-accelerated-tapering-294436","IFA Magazine","b","www.ifamagazine.com","1394470371550
4","Fed risks falling 'behind the curve', Charles Plosser says","http://www.ifamagazine.com/news/fed-risks-falling-behind-the-curve-charles-plosser-says-294430","IFA Magazine","b","www.ifamagazine.com","1394470371793
5","Fed's Plosser: Nasty Weather Has Curbed Job Growth","http://www.moneynews.com/Economy/federal-reserve-charles-plosser-weather-job-growth/2014/03/10/id/557011","Moneynews","b","www.moneynews.com","1394470372027
6","Plosser: Fed May Have to Accelerate Tapering Pace","http://www.nasdaq.com/article/plosser-fed-may-have-to-accelerate-tapering-pace-20140310-00371","NASDAQ","b","www.nasdaq.com","1394470372212
This is my sample csv file
> amex#1.0.0 start /home/agam/projects/AMEX
> node index.js
(node:6478) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
listening on port 3000
Conected to database: amex
### [object Object]
this is the thing it is printing
// 1) Express for nodejs
const express = require('express');
const app = express();
const template = require('./routes/template');
const upload = require('./routes/upload');
const path = require('path');
// const fileUpload = require('express-fileupload');
const router = express.Router();
const fu = require('./routes/fileUpload')(router);
//const carts = require('./routes/carts')(router);
// 5) body parser
const bodyParser = require('body-parser');
const cors = require('cors'); // CORS is a node.js package for providing a Connect/Express middleware that can be used to enable CORS with various options.
// 2) Mongodb connection
var mongoose = require('mongoose');
const config = require('./config/database');
mongoose.connect(config.uri, (err) => {
if (err) {
console.log('error ' + err);
} else {
console.log('Conected to database: ' + config.db);
}
});
app.use(cors({ origin: 'http://localhost:4200' }));
// 5) put bodyparser code before the routes (converts request to req.body)
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// 3) connect node.js to angular
app.use(express.static(__dirname + '/client/dist/'));
// app.use(fileUpload());
app.use('/fu', fu); // Use Product routes in application
//app.use('/carts', carts);
//
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname + '/client/dist/index.html'));
});
app.listen(3000, () => {
console.log('listening on port 3000');
});
this is my index.js file which you are expecting
Hi I have done a few changes in your StackBiltz example, so I'm able to achieve the payload to be posted via a post call to in the form of JSON array and created a service which accepts this payload and on subscription passes the payload to your node post api
Created a function named pass
test.component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
import { FileUtil } from './file.util';
import { Constants } from './test.constants';
import {TestService} from './test.service';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
fileImportInput: any;
data;
csvRecords:any = [];
constructor(private _router: Router,
private _fileUtil: FileUtil,private testService:TestService
) { }
ngOnInit() {
}
// METHOD CALLED WHEN CSV FILE IS IMPORTED
fileChangeListener($event): void {
var text = [];
var target = $event.target || $event.srcElement;
var files = target.files;
if (Constants.validateHeaderAndRecordLengthFlag) {
if (!this._fileUtil.isCSVFile(files[0])) {
alert("Please import valid .csv file.");
this.fileReset();
}
}
var input = $event.target;
var reader = new FileReader();
reader.readAsText(input.files[0]);
reader.onload = (data) => {
let csvData = reader.result;
let csvRecordsArray = csvData.split(/\r\n|\n/);
var headerLength = -1;
if (Constants.isHeaderPresentFlag) {
let headersRow = this._fileUtil.getHeaderArray(csvRecordsArray, Constants.tokenDelimeter);
headerLength = headersRow.length;
}
this.csvRecords = this._fileUtil.getDataRecordsArrayFromCSVFile(csvRecordsArray,
headerLength, Constants.validateHeaderAndRecordLengthFlag, Constants.tokenDelimeter);
this.passThisFunction(this.csvRecords);
console.log('this.csvRecords',this.csvRecords);
if (this.csvRecords == null) {
//If control reached here it means csv file contains error, reset file.
this.fileReset();
}
}
reader.onerror = function () {
alert('Unable to read ' + input.files[0]);
};
};
fileReset() {
this.fileImportInput.nativeElement.value = "";
this.csvRecords = [];
}
passThisFunction(records:any){
console.log('inside function call');
console.log('records',records);
let json=JSON.stringify(records);
console.log('jsonified',json);
var str = json.replace(/},/g, "},\r\n");
console.log('das' + str);
this.testService.postCsvToMongo(str).subscribe((data) => {
console.log(data);
});
}
}
test.component.html
<h4>Read .CSV File using Angular2, JQuery and Bootstrap</h4>
<table>
<tr>
<td>
<input type="file"
#fileImportInput
name="File Upload"
id="txtFileUpload"
class="btn btn-primary"
(change)="fileChangeListener($event)"
accept=".csv"
/>
</td>
</tr>
</table>
<div>
<table class="table table-responsive table-hover" border="1"
style="width : 50%;">
<tbody>
<ng-container >
<tr >
<td *ngFor="let csvRec of csvRecords;let i=index">{{csvRec}}</td>
</tr>
</ng-container>
</tbody>
</table>
</div>
file.util.ts
import { Injectable } from '#angular/core';
#Injectable()
export class FileUtil {
constructor() {}
isCSVFile(file) {
return file.name.endsWith(".csv");
}
getHeaderArray(csvRecordsArr, tokenDelimeter) {
let headers = csvRecordsArr[0].split(tokenDelimeter);
let headerArray = [];
for (let j = 0; j < headers.length; j++) {
headerArray.push(headers[j]);
}
return headerArray;
}
validateHeaders(origHeaders, fileHeaaders) {
if (origHeaders.length != fileHeaaders.length) {
return false;
}
var fileHeaderMatchFlag = true;
for (let j = 0; j < origHeaders.length; j++) {
if (origHeaders[j] != fileHeaaders[j]) {
fileHeaderMatchFlag = false;
break;
}
}
return fileHeaderMatchFlag;
}
getDataRecordsArrayFromCSVFile(csvRecordsArray, headerLength,
validateHeaderAndRecordLengthFlag, tokenDelimeter) {
console.log(csvRecordsArray);
console.log(headerLength);
console.log(validateHeaderAndRecordLengthFlag);
console.log(tokenDelimeter);
var dataArr:any = [];
for (let i = 0; i < csvRecordsArray.length; i++) {
let data = csvRecordsArray[i].split(tokenDelimeter);
if(validateHeaderAndRecordLengthFlag && data.length != headerLength){
if(data==""){
alert("Extra blank line is present at line number "+i+", please remove it.");
return null;
}else{
alert("Record at line number "+i+" contain "+data.length+" tokens, and is not matching with header length of :"+headerLength);
return null;
}
}
dataArr=data;
console.log('dataArr',dataArr);
}
return dataArr;
}
}
test.service.ts
import{Injectable} from '#angular/core';
import{Http} from '#angular/http';
import {map} from 'rxjs/operators';
#Injectable()
export class TestService{
API_URL:string='your api url';
constructor(private http:Http){}
postCsvToMongo(csvJson:any){
return this.http.post(this.API_URL,csvJson)
.pipe(map((res)=>console.log(res)));
}
}

Categories

Resources