NodeJS Html-pdf: fs.readfilesync how to async/await - javascript

I have a problem with my html-pdf document creation. The problem is that often the code runs to fast to complete the process of pdf-docutment creation. The Processes consists out of building an HTML-String by replacing placeholders in an Html file. Below you see the code what happens afterwards.
Object.keys(setter).forEach(function(element, key, _array) {
var regex = new RegExp(element, "g");
data = data.replace(regex, setter[element])
})
var result = data;
fs.writeFile(mergeFileRes, result, 'utf8', function (err) {
if(err) {
console.log(err);
return;
} else {
let html2 = fs.readFileSync(mergeFileRes, 'utf8');
let options = {
format: 'a4' ,
"directory" : "/tmp",
};
if(html2){
pdf.create(html2, options).toStream(function(err, stream2){
if(err) console.log(err);
stream2.pipe(res);
stream2.on('end', function () {
try{
fs.unlink(mergeFileRes)
console.log(3090, "deleted file");
}
catch (err){
console.log(3090, "Did not delete file");
}
});
});
} else {
}
}
});
My problem is that in many cases the html2 variable is not yet created before the pdf.create process starts. This is probably because the readFileSync takes too long to finish.
I was wondering, how can I fix this. How can I make the pdf.create wait for the readFileSync to finish and the html2 variable to be filled.

You can use fs.readFile to read the file asynchronously and html2 will be available within the callback function.
Object.keys(setter).forEach(function(element, key, _array) {
var regex = new RegExp(element, "g");
data = data.replace(regex, setter[element])
})
var result = data;
fs.writeFile(mergeFileRes, result, 'utf8', function (err) {
if(err) {
console.log(err);
return;
} else {
fs.readFile(mergeFileRes, 'utf8', function(err, html2){
if (err) throw err;
let options = {
format: 'a4' ,
"directory" : "/tmp",
};
pdf.create(html2, options).toStream(function(err, stream2){
if(err) console.log(err);
stream2.pipe(res);
stream2.on('end', function () {
try{
fs.unlink(mergeFileRes)
console.log(3090, "deleted file");
}
catch (err){
console.log(3090, "Did not delete file");
}
});
});
});
}
});

Related

Wait for function to finish to do something else node.js formidable

so my issue here is that the console.log() at the end of the code always prints before the parse for the formidable form is finish and i dont know how to avoid this
exports.scrape = (req,res) => {
let form = new formidable.IncomingForm();
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
if (err) {
return res.status(400).json({
error: 'Image could not be uploaded'
});
}
const { endpoint } = fields;
if (!endpoint ) {
return res.status(400).json({
error: 'All fields are required'
});
}
if (files.file) {
if (files.file.size > 1000000) {
return res.status(400).json({
error: 'Image should be less than 1mb in size'
});
}
var oldPath = files.file.path;
console.log(oldPath);
var newPath = path.join(__dirname, '../src/files/csv')
+ '/'+files.file.name
var rawData = fs.readFileSync(oldPath)
fs.writeFile(newPath, rawData, function(err){
if(err) console.log(err)
return console.log(newPath);
})
}
})
console.log("test!");
}
And then when the parse is complete make another action bc i need the file being created to later use it in another script that will be initialized when the parse is over, that would bere where the console.log("test!") is
Get a basic understanding of how callbacks work. Then you realize that putting console.log at the bottom is not chronologically the end.

Express.js- Calling three Dependent MongoDB queries sequentially for each loop

I have to insert multiple different JSON objects in MongoDB and then check whether the some of the data already exist in the database and run another query based on whether the data exists or not for each JSON Object. How can I do in expressjs? I am using mongojs package for working with MongoDB. The code I typed is below:
app.post('/addcard/:id', function(req, res) {
console.log("Received Add Card Request");
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth();
var day = date.getDate();
var yrval = req.body.yrval;
var monval = req.body.monval;
var dateval = req.body.dateval;
for (var i=0;i<req.body.phone.length;i++){
//console.log(i);
var card = new Card({
cardType : req.body.cardtype,
cardTitle : req.body.cardtitle,
allowMultipleStore : false,
phoneNumber : req.body.phone[i],
messageUser : req.body.message,
expiryDate : new Date(year+yrval,month+monval,day+dateval),
creditPoints : req.body.creditpoints,
punchCount : req.body.punch,
messageReachPunchLimit : req.body.limitmessage,
merchantUsersId : mongoose.Types.ObjectId(req.body.merchantuserid),
merchantId : mongoose.Types.ObjectId(req.params.id)
});
console.log(card);
db.carddata.insert(card, function (err,docInserted){
// console.log(card);
console.log(i);
if (err) throw err;
db.userdata.find({phoneNumber:req.body.phone},function (err,docs){
console.log("hiss");
if (err) throw err;
if (docs.length!=0){
var carduser = new CardUsersAssignment({
cardId : docInserted._id,
userId : docs[0]._id,
remainingCreditPoints : req.body.creditpoints,
remainingPunchCount : req.body.punch
});
db.carduser.insert(carduser,function (err){
console.log(" Card Details saved successfully_existing");
//console.log(i);
})
}//If (docs.length!=0)
else{
console.log(" Card Details saved successfully");
}
})//Finding by PhoneNumber
console.log(i+1);
})//Insert Function
console.log("hi");
} // End of For Loop
res.json({
success:true,
message:"Hello. You did it!"
});
});
This code is written as if I were writing for sequential execution. I know that NodeJS is asynchronous. I tried async.waterfall but it is giving error with the mongodb query function. Any help would be great. I am a NodeJS noob. Links to article which discuss similar scenarios would also be great.
You can achieve this using async library.
There is two way to do it.
Use async each to iterate your data and inside each check data is first check data is already exist or not, based on find result you can return or insert the doc.
It is the same as 1st, the only different is you just can to use waterfall for find and insert.
First Approach:
async.each(req.body.phone, function(data, callback) {
// Create card Info
db.carddata.insert(card, function (err,docInserted){
if (err) {throw err;}
db.userdata.find({phoneNumber:req.body.phone},function (err,docs){
if (err) {throw err;
} else if ( docs.length ){
// create carduser data
db.carduser.insert(carduser,function (err){
if (err) {throw err;}
callback();
}
} else {
console.log(" Card Details saved successfully");
callback();
}
}
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
Second Approach:
async.each(req.body.phone, function(data, callback) {
//create card data
let data = {}
data.phone = req.body.phone;
data.docInserted = data.docInserted;
data.cardata = cardData;
async.waterfall([
insertCard,
updateDataFind,
cardDataInsert,
async.apply('insertCard', data)
], function (err, result) {
if(err){
if(err.success){
callback();
}
throw err;
}
callback();
});
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
function insertCard(data, callback){
db.carddata.insert(card, function (err,data.docInserted){
if(err){throw err;}
callback(null, data);
}
}
function updateDataFind(data, callback){
db.userdata.find({phoneNumber:data.phone},function (err,docs){
if (err) {throw err;}
else if (docs.length!=0){ callback(null, data); }
else { callback({success:true}) }
}
}
function cardDataInsert(data, callback){
// create card user or pass from data.
db.carduser.insert(carduser,function (err){
if (err) {throw err;}
callback(null, data);
}
}

returning data from node mssql execute functions

I'm using mssql(Microsoft SQL Server client for Node.js) package from npm.I'm trying to execute a stored procedure residing in my sql server database.Everything works fine.However what I want to do is return the recordsets so that i can export this to be used in other module.Below is what I'm trying to do.
function monthlyIceCreamSalesReport (scope){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return;
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
}
else {
console.log(recordsets[0]); // successfully receiving the value
}
connObj.conn.close();
});
});
console.log('check for recordsets', recordsets[0]); // undefined
return recordsets[0];
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
As shown in the code snippet, since the value of recordsets[0] is undefined, exporting this function is of no use.
You can't return this way in async nature. You can get it by passing the callback function
Try to give a callback function like this
function monthlyIceCreamSalesReport(scope, callback) { // pass a callback to get value
var connObj = connConfig();
connObj.conn.connect(function(err) {
if (err) {
console.log(err);
return;
}
connObj.req.input('Month', 4);
connObj.req.input('Year', 2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue) {
if (err) {
console.log(err);
} else {
console.log(recordsets[0]);
connObj.conn.close();
return callback(null, recordsets[0]); //return as a callback here and get that value in callback from where you called this function
}
});
});
}
var sqlServerObj = {
monICSalesReport: monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;
Note: See the comment to understand the changes
recordsets[0] is undefinded, because is defined only in connObj.req.execute function scope. You may do this in this way:
function monthlyIceCreamSalesReport (scope, cb){
var connObj = connConfig();
connObj.conn.connect(function(err){
if(err){
console.log(err);
return cb(Error("Something wrong"));
}
connObj.req.input('Month',4);
connObj.req.input('Year',2016);
connObj.req.execute('<myStoredProcedure>', function(err, recordsets, returnValue){
if(err){
console.log(err);
connObj.conn.close();
return cb(Error("Something wrong"));
}
else {
console.log(recordsets[0]); // successfully receiving the value
connObj.conn.close();
return cb(recordsets[0]);
}
});
});
}
var sqlServerObj = {
monICSalesReport : monthlyIceCreamSalesReport,
};
module.exports = sqlServerObj;

Variable not being remembered in JSON

I have some code that loops through a directory and retrieves the file name of each file. The code then retrieves the contents of each file (usually a number or a short text).
var config = {};
config.liveProcValues = {};
var path = require('path');
walk = function(dir, done) {
var results = {};
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
fs.readFileSync(file, 'utf8', function(err, data) {
if (err) {
contents = err;
} else {
contents = data;
}
console.log(filename + " - " + contents);
filename = file.replace(/^.*[\\\/]/, '');
config.liveProcValues[filename] = contents;
});
The console.log line successfully outputs the right information, however when trying to store it into JSON:
config.liveProcValues[filename] = contents;
It simply does remember the information.
walk("testdirectory", function(err, results) {
if (err) throw err;
});
// Output the configuration
console.log(JSON.stringify(config, null, 2));
You have to make sure that you are accessing the data after the filesystem was traversed. In order to do that you have to move the console.log into the walk callback:
walk("testdirectory", function(err, results) {
if (err) throw err;
// Output the configuration
console.log(JSON.stringify(results, null, 2));
});
See Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference for more info.
That alone won't solve the issue though, since you have a couple of logic errors in your code. You are trying to treat an object as an array (results.concat) and you are not always calling done when you are done (in particular, you are not calling done after you finished reading the files in a directory).
Here is a version that should come closer do what you want.
This uses Object.assign to merge two objects, which is not available in Node yet, but you can find modules that provide the same functionality.
Note thats I also removed the whole config object. It's cleaner if you work with results.
var path = require('path');
function walk(dir, done) {
var results = {};
fs.readdir(dir, function(err, list) {
if (err) return done(err);
if (!list.length) return done(null, results);
var pending = list.length;
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
if (!err) {
// Merge recursive results
Object.assign(results, res);
}
if (!--pending) done(null, results);
});
} else {
fs.readFile(file, 'utf8', function(err, data) {
var contents = err || data;
console.log(file + " - " + contents);
file = file.replace(/^.*[\\\/]/, '');
// Assign the result to `results` instead of a shared variable
results[file] = contents;
// Need to call `done` if there are no more files to read
if (!--pending) done(null, results);
});
}
});
});
});
}
But instead of writing your own walk implementation, you could also use an existing package.

How to read file in Node?

I want to read file but if file not available on particular path than gives an error.I want to create a file if not exist and get data value is null. I used these code but not working please any one help me?
fs.readFile(path, 'utf8', function (err,data) {
if (err) {
return console.log(err); //Here throw error if not available
}
console.log(data);
fileData = data;
});
I used below code it's also not working.I want read all data from file what should i put on '?' in following code?
fs.open(path, 'w+', function(err, data) {
if (err) {
console.log("ERROR !! " +err);
} else {
fs.read(data, ? , 0, ? , null, function(err) {
if (err) console.log("ERROR !! " +err);
});
}
});
There is an error in your first code snippet, try:
fs.readFile(path, {encoding: 'utf8'}, function (err, data) {
if (err) throw err;
console.log(data);
});
The error was in the "encoding utf". It should be an object.
See: http://nodejs.org/api/fs.html#fs_fs_readfile_filename_options_callback
if(fs.existsSync(file_path))
{
var file_content = fs.readFileSync(file_path, 'utf-8');
} else {
var file_content = fs.writeFileSync(file_path, '');
}

Categories

Resources