I'm using Node.js and trying to render an EJS template file. I figured out how to render strings:
var http = require('http');
var ejs = require('ejs');
var server = http.createServer(function(req, res){
res.end(ejs.render('Hello World'));
});
server.listen(3000);
How can I render an EJS template file?
There is a function in EJS to render files, you can just do:
ejs.renderFile(__dirname + '/template.ejs', function(err, data) {
console.log(err || data);
});
Source: Official EJS documentation
var fs = require('fs');
var templateString = fs.readFileSync('template.ejs', 'utf-8');
and then you do your thing:
var server = http.createServer(function(req, res){
res.end(ejs.render(templateString));
});
All you have to do is compile the file as a string (with optional local variables), like so:
var fs = require('fs'), ejs = require('ejs'), http = require('http'),
server, filePath;
filePath = __dirname + '/sample.html'; // this is from your current directory
fs.readFile(filePath, 'utf-8', function(error, content) {
if (error) { throw error); }
// start the server once you have the content of the file
http.createServer(function(req, res) {
// render the file using some local params
res.end(ejs.render(content, {
users: [
{ name: 'tj' },
{ name: 'mape' },
{ name: 'guillermo' }
]
});
});
});
#ksloan's answer is really good. I also had the same use case and did little bit of digging. The function renderFile() is overloaded. The one you will need mostly is:
renderFile(path: string,data, cb)
for example:
ejs.renderFile(__dirname + '/template.ejs', dataForTemplate, function(err, data) {
console.log(err || data)
})
where dataForTemplate is an object containing values that you need inside the template.
There's a synchronous version of this pattern that tightens it up a little more.
var server = http.createServer(function(req, res) {
var filePath = __dirname + '/sample.html';
var template = fs.readFileSync(filePath, 'utf8');
res.end(ejs.render(template,{}));
});
Note the use of readFileSync(). If you specify the encoding (utf8 here), the function returns a string containing your template.
The answer of #ksloan should be the accepted one. It uses the ejs function precisely for this purpose.
Here is an example of how to use with Bluebird:
var Promise = require('bluebird');
var path = require('path');
var ejs = Promise.promisifyAll(require('ejs'));
ejs.renderFileAsync(path.join(__dirname, 'template.ejs'), {context: 'my context'})
.then(function (tpl) {
console.log(tpl);
})
.catch(function (error) {
console.log(error);
});
For the sake of completeness here is a promisified version of the currently accepted answer:
var ejs = require('ejs');
var Promise = require('bluebird');
var fs = Promise.promisifyAll(require('fs'));
var path = require('path');
fs.readFileAsync(path.join(__dirname, 'template.ejs'), 'utf-8')
.then(function (tpl) {
console.log(ejs.render(tpl, {context: 'my context'}));
})
.catch(function (error) {
console.log(error);
});
Use ejs.renderFile(filename, data) function with async-await.
To render HTML files.
const renderHtmlFile = async () => {
try {
//Parameters inside the HTML file
let params = {firstName : 'John', lastName: 'Doe'};
let html = await ejs.renderFile(__dirname + '/template.html', params);
console.log(html);
} catch (error) {
console.log("Error occured: ", error);
}
}
To render EJS files.
const renderEjsFile = async () => {
try {
//Parameters inside the HTML file
let params = {firstName : 'John', lastName: 'Doe'};
let ejs = await ejs.renderFile(__dirname + '/template.ejs', params);
console.log(ejs);
} catch (error) {
console.log("Error occured: ", error);
}
}
Related
i have code to make pdf and succeeded in downloading and opening it, but i want to send pdf to my server on node js, and i have made app.post on server but i can't make pdf become base64 and save it on server
in frontend
<script type="text/javascript">
function genPDF() {
html2canvas(document.getElementById('testDiv')).then(function (canvas) {
var img = canvas.toDataURL('image/png');
var doc = new jsPDF('landscape');
doc.addImage(img, 'png', 10, 10);
var temp = doc.save('test.pdf');
var post = new XMLHttpRequest();
post.open("POST", "/receive");
post.send(temp);
}
</script>
Download PDF
in server
app.post('/receive', function (request, respond) {
var body = '';
var filePath = './static' + '/document/Document.pdf';
//
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var data = body.replace(/^data:image\/\w+;base64,/, "");
var buf = new Buffer(data, 'base64');
fs.writeFile(filePath, buf, function (err) {
if (err) throw err
respond.end();
});
});
});
how to send var temp = doc.save('test.pdf'); server and generate pdf to base64?
Use the below code this will help you.
IN FE
<script type = "text/javascript">
function genPDF() {
html2canvas(document.getElementById('testDiv')).then(function (canvas) {
var img = canvas.toDataURL('image/png');
var doc = new jsPDF('landscape');
doc.addImage(img, 'png', 10, 10);
var temp = doc.save('test.pdf');
var data = new FormData();
data.append("pdf_file", temp);
var post = new XMLHttpRequest();
post.open("POST", "/receive");
post.send(data);
}
</script>
<a href = "javascript:genPDF()" > Download PDF </a>
IN BE
const fs = require('fs');
const multipartMiddleware = require('connect-multiparty')();
const express = require('express');
const app = express();
const port = 8000;
const filePath = './static' + '/document/Document.pdf';
app.post('/', multipartMiddleware, (request, response) => {
fs.readFile(request.files.pdf_file.path, (err, data) => {
fs.writeFile(filePath, data, function (err) {
if (err) throw err;
response.send('Done')
});
})
})
app.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log(`server is listening on ${port}`)
});
I want to stream a file upload request in multipart/form-data to another server and change some fields name at the same time.
I don't want to store temporarily a file on disk and don't want to store the file completely in memory either.
I tried to use multer, busboy and multiparty. I think I got closer by using custom Transform streams but it is not working yet.
const express = require('express');
const request = require('request');
const { Transform } = require('stream');
const router = express.Router();
class TransformStream extends Transform {
_transform(chunk, encoding, callback) {
// here I tried to manipulate the chunk
this.push(chunk);
callback();
}
_flush(callback) {
callback();
}
}
router.post('/', function pipeFile(req, res) {
const transformStream = new TransformStream();
req.pipe(transformStream).pipe(request.post('http://somewhere.com'));
res.sendStatus(204);
});
I tried to manipulate chunks in _transform without success (EPIPE). It sounds quit hacky, are they any better solutions ?
Here is a solution using replacestream along with content-disposition.
const replaceStream = require('replacestream');
const contentDisposition = require('content-disposition');
router.post('/', function pipeFile(req, res) {
let changeFields = replaceStream(/Content-Disposition:\s+(.+)/g, (match, p1) => {
// Parse header
let {type, parameters} = contentDisposition.parse(p1);
// Change the desired field
parameters.name = "foo";
// Prepare replacement
let ret = `Content-Disposition: ${type}`;
for(let key in parameters) {
ret += `; ${key}="${parameters[key]}"`;
}
return ret;
})
req.pipe(changeFields)
.pipe(request.post('http://somewhere.com'))
.on('end', () => {
res.sendStatus(204);
});
});
This worked for a single file multipart upload using express, multiparty, form-data, pump and got.
const stream = require('stream');
const express = require('express');
const multiparty = require("multiparty");
const got = require("got");
const FormData = require('form-data');
const pump = require('pump');
const app = express();
app.post('/upload', (req, res) => {
const url = "<<multipart image upload endpoint>>";
var form = new multiparty.Form();
form.on("part", function(formPart) {
var contentType = formPart.headers['content-type'];
var formData = new FormData();
formData.append("file", formPart, {
filename: formPart.filename,
contentType: contentType,
knownLength: formPart.byteCount
});
const resultStream = new stream.PassThrough();
try {
// Pipe the formdata to the image upload endpoint stream and the result to the result stream
pump(formData, got.stream.post(url, {headers: formData.getHeaders(), https:{rejectUnauthorized: false}}), resultStream, (err) =>{
if(err) {
res.send(error);
}
else {
// Pipe the result of the image upload endpoint to the response when there are no errors.
resultStream.pipe(res);
}
resultStream.destroy();
});
}
catch(err) {
resultStream.destroy();
console.log(err);
}
});
form.on("error", function(error){
console.log(error);
})
form.parse(req);
});
This is the code written by me to get all the js files in a directory to be minified:
var http = require('http');
var testFolder = './tests/';
var UglifyJS = require("uglify-js");
var fs = require('fs');
var glob = require("glob");
var fillnam="";
hello();
function hello()
{
glob("gen/*.js", function (er, files) {
//console.log(files);
for(var i=0;i<files.length;i++)
{
fillnam=files[i];
console.log("File Name "+fillnam);
fs.readFile(fillnam, 'utf8', function (err,data)
{
if (err) {
console.log(err);
}
console.log(fillnam+" "+data);
var result = UglifyJS.minify(data);
var gtemp_file=fillnam.replace(".js","");
console.log(gtemp_file);
fs.writeFile(gtemp_file+".min.js", result.code, function(err) {
if(err) {
console.log(err);
} else {
console.log("File was successfully saved.");
}
});
});
}
});
}
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('Hello World!');
}).listen(8080);
As a result respective minified js files with same name with .min.js should be formed in the same directory.
But what I am getting is a single file with all files data over written. Like for example if there are two files in a directory a.js and b.js with content:
var a=10;var b=20;
var name="stack";
What I'm getting is single file a.min.js with file content:
var a=10tack;
Please help.
You need to collect all file contents first, concat them and then run UglifyJS.minify on them to be able to save it as a single file.
Something like this (not fully tested)
const testFolder = './tests/';
const UglifyJS = require("uglify-js");
const fs = require('fs');
const readFile = require('util').promisify(fs.readFile);
const glob = require("glob");
function hello() {
glob("gen/*.js", async(er, files) {
let data = [];
for (const file of files) {
const fileData = await readFile(file, {
encoding: 'utf-8'
});
data.push(fileData);
}
const uglified = UglifyJS.minify(data.join('\n'));
fs.writeFile('main.min.js', uglified);
});
}
hello();
I am new in angular. I have a set of images & I want to display it on to the client browser on a load of the page.
Is it possible or not?
I am able to send a single file but not multiple files now I am stuck can someone help me.
Thanks for help
router.get('/getList', function(req, res, next) {
var fileNames = [];
fileNames = readDir.readSync('/NodeWorkspace/uploads/output/', ['**.png']);
var data = {};
fileNames.forEach(function(filename) {
filepath = path.join(__dirname, '../../uploads/output') + '/' + filename;
fs.readFile(path.join(__dirname, '../../uploads/output') + '/' + filename, function(err, content) {
if (!err) {
console.log(content);
}
});
});
//res.sendFile(path.join(__dirname,'../../uploads/output/', fileNames[0]));
response.data = fileNames;
res.json(response);
});
Convert fs callback to promise and read all parallel once done send response.
const fs = require('fs');
const db = require('../db');
const readFile = util.promisify(fs.readFile);
router.get('/getList', function (req, res, next) {
var fileNames = [];
fileNames = readDir.readSync('/NodeWorkspace/uploads/output/', ['**.png']); // use async function instead of sync
var data = {};
const files = fileNames.map(function (filename) {
filepath = path.join(__dirname, '../../uploads/output') + '/' + filename;
return readFile(filepath); //updated here
});
Promise.all(files).then(fileNames => {
response.data = fileNames;
res.json(response);
}).catch(error => {
res.status(400).json(response);
});
});
I have created a Node.js Webservice which takes Json object in the post body and in the same object I need to pass the image/video (not sure whether its possible) media files and the same media file needs to up uploaded to Azure Blob Storage.
Azure storage gives library where we upload the stream. But how do I upload the files to node.js server from Apps before uploading to Azure blob storage.
The concept has to work on Windows, Android and IOS platform.
If your server is hosted on Web apps and assuming it’s built by expressjs, #Alex Lau provided a good point.
Also, here are another 2 libs for express handling upload files. I’d like to give you some code snippets to handle upload files and put to blob storage in expressjs with these libs:
1,connect-busboy
var busboy = require('connect-busboy');
var azure = require('azure-storage');
var fs = require('fs');
var path = require('path');
var blobsrv = azure.createBlobService(
accountname,
accountkey
)
router.post('/file', function (req, res, next) {
var fstream;
var uploadfolder = path.join(__dirname, '../files/');
if (mkdirsSync(uploadfolder)) {
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename) {
console.log("Uploading: " + filename);
fstream = fs.createWriteStream(uploadfolder + filename);
file.pipe(fstream);
fstream.on('close', function () {
//res.redirect('back');
blobsrv.createBlockBlobFromLocalFile('mycontainer',filename,uploadfolder + filename, function (error, result, response) {
if (!error) {
res.send(200, 'upload succeeded');
} else {
res.send(500, 'error');
}
})
});
});
}
})
function mkdirsSync(dirpath, mode) {
if (!fs.existsSync(dirpath)) {
var pathtmp;
dirpath.split("\\").forEach(function (dirname) {
console.log(dirname);
if (pathtmp) {
pathtmp = path.join(pathtmp, dirname);
}
else {
pathtmp = dirname;
}
if (!fs.existsSync(pathtmp)) {
if (!fs.mkdirSync(pathtmp, mode)) {
return false;
}
}
});
}
return true;
}
2,formidable
var formidable = require('formidable')
router.post('/fileform', function (req, res, next) {
var form = new formidable.IncomingForm();
form.onPart = function (part){
part.on('data', function (data){
console.log(data);
var bufferStream = new stream.PassThrough();
bufferStream.end(data);
blobsrv.createBlockBlobFromStream('mycontainer', part.filename, bufferStream, data.length, function (error, result, response){
if (!error) {
res.send(200,'upload succeeded')
} else {
res.send(500,JSON.stringify(error))
}
})
})
}
form.parse(req);
//res.send('OK');
})
If you are using a Mobile Apps with Node.js as a backend to handle these workflows, we can create a custom API, and transfer media content in base64 code.
In mobile app:
var azure = require('azure');
var fs = require('fs');
var path = require('path');
exports.register = function (api) {
api.post('upload',upload);
}
function upload(req,res){
var blobSvc = azure.createBlobService(
req.service.config.appSettings.STORAGE_ACCOUNTNAME,
req.service.config.appSettings.STORAGE_ACCOUNTKEY
);
var decodedImage = new Buffer(req.body.imgdata, 'base64');
var tmpfilename = (new Date()).getTime()+'.jpg';
var tmpupload = 'upload/';
mkdirsSync(tmpupload);
var filePath = tmpupload+tmpfilename;
fs.writeFileSync(filePath,decodedImage); blobSvc.createBlockBlobFromFile(req.body.container,tmpfilename,filePath,req.body.option,function(error,result,response){
if(!error){
res.send(200,{result:true});
}else{
res.send(500,{result:error});
}
})
}
In mobile application, I used iconic framework integrated ng-cordova plugin to handle camera events.
Here are controller and server script snippet. For your information:
Controller js:
$scope.getpic = function(){
var options = {
quality: 10,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA,
allowEdit: false,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 100,
targetHeight: 100,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: false
};
$cordovaCamera.getPicture(options).then(function(imageData) {
console.log(imageData);
return blobService.uploadBlob(objectId,imageData);
}, function(err) {
// error
}).then(function(res){
console.log(JSON.stringify(res));
});
};
Server js(blobService):
factory('blobService',function($q){
return{
uploadBlob:function(container,imgdata,option){
var q = $q.defer();
mobileServiceClient.invokeApi('blobstorage/upload',{
method:"post",
body:{
container:container,
imgdata:imgdata,
option:{contentType:'image/jpeg'}
}
}).done(function(res){
console.log(JSON.stringify(res.result));
if(res.result.blob !== undefined){
q.resolve(res.result.blob);
}
if(res.result.url !== undefined){
q.resolve(res.result.url);
}
});
return q.promise;
}
}
})
Perhaps you may consider using multipart/form-data instead of JSON as there is a good library (expressjs/multer, assuming you are using express) to handle file uploading in node.js.
As long as you get the file from multer, the rest can be very simple as below:
app.post('/profile', upload.single('avatar'), function (req, res, next) {
blobService.createBlockBlobFromLocalFile('avatars', req.file.originalname, req.file.path, function(error, result, response) {
});
});
For iOS and Android, there are also plenty of libraries that allow multipart/form-data request like AFNetworking in iOS and OkHttp in Android.