I am using using EJS templates with Node.js and Express. I am trying to pass a request parameter to my EJS template. It is working, however, for some reason my console log is reporting something strange.
Versions:
Node 0.10.26
Express 4.6.1
EJS 0.8.5
Here is the route that handles the ejs template:
var express = require('express');
var router = express.Router();
var data = require('../data.json');
var pkg = require('../../package.json');
router.get('/', function(req, res) {
res.render('index',
{
'acs' : data.acs,
'products' : data.products,
'pkg' : pkg,
'debug' : req.param('debug')
});
});
module.exports = router;
This is the console log (I replaced anything long with "..." to save space)
var __stack = {
lineno: 1,
input: "<!DOCTYPE html>\n<html lang=\"en\"> ... </html>\n",
filename: "/web/app/views/index.ejs" };
function rethrow(err, str, filename, lineno){
var lines = str.split('\n')
, start = Math.max(lineno - 3, 0)
, end = Math.min(lines.length, lineno + 3);
// Error context
var context = lines.slice(start, end).map(function(line, i){
var curr = i + start + 1;
return (curr == lineno ? ' >> ' : ' ')
+ curr
+ '| '
+ line;
}).join('\n');
// Alter exception message
err.path = filename;
err.message = (filename || 'ejs') + ':'
+ lineno + '\n'
+ context + '\n\n'
+ err.message;
throw err;
}
try {
var buf = [];
with (locals || {}) { (function(){
buf.push('<!DOCTYPE html>\n<html lang="en">...</html>\n'); })();
}
return buf.join('');
} catch (err) {
rethrow(err, __stack.input, __stack.filename, __stack.lineno);
}
Like I said, it is working, however I can't tell why this is being logged in the console. Thanks for the help!
The problem is that the second argument passed to res.render() is passed to both the rendering engine AND your template. Because of this behavior, ejs (at least through 1.0 as of this writing), looks for a debug property in that object to determine if debug information will be printed.
Related
The first API request successfully send a response. However, when I do another GET request the error "write after end" is given.
When I turn off .pipe(addThing) then it does work on consecutive calls.
Is the through2-map function ending the connection or response somehow?
const fs = require('fs');
const express = require("express");
const route = express.Router();
const map = require("through2-map")
const csv2json = require("csv2json");
const firstThreeDigits = new RegExp(/[\s]*\d{3}/);
route.get("/", function(_, res){
fs.createReadStream('./data/data.csv')
.pipe(addThing)
.pipe(csv2json({
separator: ';'
}))
.pipe(res)
});
const addThing = map(function (chunk) {
const chunkArr = chunk.toString().split('\n');
const chunkWithNumber = chunkArr.map((line, index) => {
if (index === 0) {
return 'Number;' + line
}
return firstThreeDigits.exec(line) + ';' + line
})
return chunkWithNumber.toString().split(',').join("\n")
});
module.exports = route;
Not sure if it's relevant, but the csv:
./data/data.csv
Thing;Latitude;Longitude
FOO-123 Banana;52.09789;3.113278
BAR-456 Monocle;52.034599;5.11235
After reading "Error: write after end" with csv-write-stream I noticed that the problem might be that the variable addThing is not created new on every consecutive call.
It was allocated in memory.
So the solution:
fs.createReadStream('./data/cameras-defb.csv')
.pipe(map(addThing))
.pipe(csv2json({
separator: ';'
}))
.pipe(res);
function addThing(chunk) {
const chunkArr = chunk.toString().split('\n');
const chunkWithNumber = chunkArr.map((line, index) => {
if (index === 0) {
return 'Number;' + line
}
return firstThreeDigits.exec(line) + ';' + line
})
return chunkWithNumber.toString().split(',').join("\n")
})
I'm trying to get the results of a search in the Rust documentation. I made this code to do it :
let HTMLParser = require('node-html-parser');
let https = require('https');
const search = "foo";
let options = {
host: "doc.rust-lang.org",
path: "/std/index.html?search=" + search
};
let request = https.get(options, (res) => {
if (res.statusCode != 200) return console.log(`An error occured : ${res.statusCode}. Retry later.`);
res.setEncoding("utf8");
let output = "";
res.on("data", (chunk) => {
output += chunk
});
res.on("end", () => {
let root = HTMLParser.parse(output);
console.log(root.querySelector(".search-results")); // print "null" because the search is not done when the request response come
});
request.end();
});
But when I run this code, I get the HTML content of the index.html page like if I requested this page without the ?search="foo". I found that the page change dynamically with some JS when we search for something, and then the base content is set to hidden and the search div become visible. So it seems that the JS didn't load when I get the request result, but I needs it to get the results of the search in the documentation. I don't know how I can do that.
Thank you in advance for your answers !
The Rust doc page does not seem to hit a backend when a search is performed. I noticed this using the browser developer tools.
It looks like the page loads a search-index which contains the readily available docs. You can use this js to search for docs. The logic is written in the main.js.
Let me know if you are looking for more info, as I have not found out how the link generation on each doc item is created.
EDIT
All the logic required to build the url is in main.js. The method is as follows. If you take a close look at the aliases.js, main.js, storage.js and search-index.js files, you can reuse almost all of it to create the links and the required search outputs.
function buildHrefAndPath(item) {
var displayPath;
var href;
var type = itemTypes[item.ty];
var name = item.name;
if (type === 'mod') {
displayPath = item.path + '::';
href = rootPath + item.path.replace(/::/g, '/') + '/' + name + '/index.html'
} else if (type === 'primitive' || type === 'keyword') {
displayPath = '';
href = rootPath + item.path.replace(/::/g, '/') + '/' + type + '.' + name + '.html'
} else if (type === 'externcrate') {
displayPath = '';
href = rootPath + name + '/index.html'
} else if (item.parent !== undefined) {
var myparent = item.parent;
var anchor = '#' + type + '.' + name;
var parentType = itemTypes[myparent.ty];
if (parentType === 'primitive') {
displayPath = myparent.name + '::'
} else {
displayPath = item.path + '::' + myparent.name + '::'
}
href = rootPath + item.path.replace(/::/g, '/') + '/' + parentType + '.' + myparent.name + '.html' + anchor
} else {
displayPath = item.path + '::';
href = rootPath + item.path.replace(/::/g, '/') + '/' + type + '.' + name + '.html'
}
return [displayPath,
href]
}
I'm trying to populate a database with pictures paths & names using Node.js.
What I am trying to do is the following :
- A function send a list of pictures as Base64 string.
- Another function receive this list, loop through it, convert it into picture and get the path back.
I'm pretty new to node.js so I might be doing something really stupid.
Here is the reception code :
app.post('/chatBot/moreinfo/create', function (req, res) {
returnList = '';
res.set('Content-Type', 'application/json');
//IF LIST IS NOT EMPTY
if (req.body.imgList.length !== 0) {
const imagePath = '/var/lib/SMImageBank/';
const regex = /^data:image\/(.*);.*$/i;
const listePicture = req.body.imgList;
// LOOPING INTO THE LIST
req.body.imgList.map ( function (element) {
const file = element;
const filetype = file.match(regex)[1];
var picLink2 = '';
const base64data = file.replace(/^data:image\/.*;base64,/, "");
const latin1data = new Buffer(base64data, 'base64').toString('latin1');
const filename = new Date().getTime() + '' + new Date().getMilliseconds() + "." + filetype;
fs.mkdir(imagePath, () => {
fs.writeFile(imagePath + filename, latin1data, "latin1", function (err, content) {
if (err) {
routerLog(req, {'type': 'error', 'content': err} );
res.sendStatus(500);
}
else {
if (process.env.NODE_ENV === "production")
picLink2 = 'http://****.fr/image/' + filename;
else if(process.env.NODE_ENV === "test")
picLink2 = 'http://dev.****.fr:8010/image/' + filename;
else if(process.env.NODE_ENV === "master")
picLink2 = 'http://dev.****.fr:8008/image/' + filename;
else{
picLink2 = 'http://*****.com:8008/image/' + filename;
}
}
});
})
console.log(picLink2);
returnList = returnList + ";" + picLink2;
});
}
MoreInfo.create(req.body, function (ret) {
res.send(ret);
routerLog(req);
})
});
What I want to do is to be able to access the variable "picLink2" from outside the writeFile & mkdir function so I can populate my returnList at each iteration. Obviously as node.js is asynchronous I can't access to picLink2 content from outside fs.writeFile() function. I know there has been a ton of question about this and lot of the answers are to put the code inside the writeFile()/readFile() function but I don't see how I can do it here since the writeFile() function is inside a map that is iterating into a list.
I'm new to the asynchronous world and I don't see how I can solve this problem.
Use writeFileSync for a synchronous operation if that doesn't hurt performance.
I wanted to remember the last page someone visited (like here)
I tried to do it with cookie-session but It's doesn't work as I a suppose.
I saw this and I tried this example for extending the session without success.
Here the code :
var session = require('cookie-session');
var express = require('express');
var app = express();
app.use( session({ secret: 'secret' }) );
app.get('/a', function (req, res) {
if(req.session.last) {
res.write("the last page was " + req.session.last + ". ");
}
req.session.last = "a";
res.end("Page A");
});
app.get('/b', function (req, res) {
if(req.session.last) {
res.write("the last page was " + req.session.last + ". ");
}
req.session.last = "b";
res.end("Page B");
});
app.get('/c', function (req, res) {
if(req.session.last) {
res.write("the last page was " + req.session.last + ". ");
}
req.session.last = "c";
res.end("Page C");
});
app.listen(8080);
Are you sure you are not getting an error in your logs along the line of "cannot write to headers after they have been sent"? Can you try moving the assigning of the session to before the res.write call? From your first link, in the comments...
"I kept getting an error that the headers couldn't be set after they'd been sent.
I modified the code so that lastPage was set before sending any body eg:
var responseText;
if(req.session.lastPage)
responseText = 'Last page was: ' + req.session.lastPage + '. ';
else
responseText = 'You\'re Awesome';
req.session.lastPage = '/awesome';
res.send(responseText);
I want to put the fallowing in a helper but i get and require it in my app.js. My current error is app is not defined. I am new to node.js so if this is a easy one dont be to hard on me.
app.locals.use({flashMessages: function(req, res) {
var html = ""
, flash = req.flash();
['error', 'info'].forEach(function(type) {
if(flash[type]) {
flash[type].forEach(function(message) {
html += "<div class='alert " + type + "'>" + message + "</div>";
});
}
});
return html; }});
You should either convert this to a function that accepts an app parameter, or you could put app into GLOBAL. See node.js global variables?