Jade / Expressjs: Pass objects from server to client - javascript

I'm trying to pass an object from my endpoint to Jade but It keeps giving me Uncaught SyntaxError: Unexpected identifier on Stat! Can someone help me please. Here is my code:
app.get('/stats', function (req, res, next) {
var stats ={
'm0t20': {a:0,b:0,c:0,d:0},
'm20t30': {a:0,b:0,c:0,d:0},
};
res.render('chart',{'stat':stats});
}
and in my jade and I cant get the value of stat:
script(type='text/javascript').
var stats= #{stat};

If you want to interpolate object from you express, the easiest and cleanest way is to serialize them.
For the moment, once interpolated, you are trying to write something like this:
var stats = [Object object];
Which isn't a valid JavaScript syntax :/
So, on the server side, serialize your object:
app.get(..., function (req, res) {
var stats = { ... };
res.render('chart', { stats: JSON.stringify(stats) });
});
And, on the client side, just use the serialized object; You'll need to use ! instead of # to prevent jade from escaping characters like quotes.
script.
var stats = !{stats};
alert(stats.myProp);
Keep in mind that you are injecting direct JavaScript code into your page.
DO NOT do that if the serialized object could contain any user input

Related

Parse a string representation of javascript without storing a file

There is a scenario where I let a client to insert a JavaScript script that should be sent my server. Actually, this script (well, should..) will export some object.
So the frontend code is something like this:
<form action="/blabla.js" method="post">
<textarea>
</form>
Then the frontend sends the input of the <textarea /> to the server.
A typical input will be something like:
module.exports = {
glagla: {
blabla: 2
},
};
The frontend will send this script, as a string, to a server.
Next step is the server needs to parse this string.
So right now, for example with express package it should look like:
import fs from 'fs';
const handler = async (req, res) => {
const input = req.body.script;
await fs.promises.writeFile('./somewhere.js', req.body.script);
const parsedObject = require('./somewhere.js');
}
I'm trying to not use the file system, but cannot find a way to do so.
I there a pure way, without using the file system to parse such a script in JS?
I think this package https://www.npmjs.com/package/vm2 is the solution.
Basically you don't need to use module.exports for this, because you dont need to create file and then include it in the code with require. You can pass just function body:
// String from frontend, which must
// contain function body
const strFn = 'return { glagla: { blabla: 2 }}';
// Create function from string
const obj = new Function(strFn);
// Run created function and access
// property of returned object
console.log(obj().glagla.blabla);
But keep in mind, that this is pretty risky, because user can pass anything from frontend to your backend to run.
If you need to pass only object with it's properties and values, it's better to utilize JSON for this purpose:
// Object on frontend side
const frontendObj = { glagla: { blabla: 2 }};
// While on frontend, convert object
// in to the JSON string
const strJSON = JSON.stringify(frontendObj);
//
// Then send this string to the server
//
// On server side parse received JSON
// string in to the JS object
const obj = JSON.parse(strJSON);
// Now you can access property of
// returned object
console.log(obj.glagla.blabla);

Node.js - how to implement api/:product_url

I am new to node.js and I am using Yeoman to fetch a product details from the list of products. I am getting data from a triple store database and converting to json. The only unique ID is in the form of URL with an hash encoded at last.
In demo.controller.js:
exports.index = function(req, res) {
res.json(response);
}
In index.js:
var controller = require('./demo.controller');
var router = express.Router();
router.get('/', controller.index);
module.exports = router;
Here, response output is the following json structure for URL/api/product_list:
[{
"url":"http://example.com/demo/32b9jkd902n2"
"product":"stack",
"name":"test",
"price":"233"
}, {
"url":"http://example.com/demo/5nf9djdkdks0"
"product":"flow",
"name":"dev",
"price":"433"
}]
Now, I want to get details of each product. something like URL/api/product_list/:product_url ?
Basically, when I access url with product_url from the list of products, I should be able to get the product details.
Can someone help me in implementing the URL with /api/product_list/:product_url with an output of single product?
So, as there is no other unique identifier besides the URL you could to one of the following:
Parse unique ID from the url to /api/product_list as id to the output and use that - /api/product_list/:id
Generate a hash (md5, sha1) of the whole url to the output as id and use that as an unique id.
Note: never used Yeoman before, so I don't know if you have some limitations from there.
I think /api/product_list/:url will not fly, and if it does, it sure will look ugly.

Send json to jade

I am sending a big json file from server to jade, but the " are replaced with: " therefor the json is unreadable/unparsable and I get this error:
Uncaught SyntaxError: Unexpected token &
I send the data like this from node:
res.render(view, {world:{name:"SomeName",width:50},otherdata:{...}});
and then get it in jade like this:
doStuff(JSON.parse(#{data}));
and here it is unreadable data which looks like:
{world:{name:"SomeName",width:50...
can I somehow disable the conversion of the quotes?
Server side within your rout you will do the following consider the object user
var user = {username:"myname"};
res.locals.user = user ;
response will be :
res.render('view');
jade view will have the variable available :
if user
script(type='text/javascript').
var user = !{JSON.stringify(user)};
Try adding app.use(bodyParser.json()); if you still have the issue
hope that helps
No experience with jade but from the language reference (http://jade-lang.com/reference/interpolation/) i guess
doStuff(JSON.parse(!{data}))
might work

Serve dynamic javascript file with nodejs

Questions
How to serve javascript file dynamically? Specifically, the scripts maintain most of its body but with some variables changable (imagine HTML Jade template, but this is for pure javascript).
Scenario
When user or browser (http GET in general) visits /file.js passing parameter api, e.g. /file.js?api=123456, I would like to output pure javascript where I can take that 123456 and put in inside of my code, dynamically. Content-Type is application/javascript.
Sample:
var api = #{req.query.api}; //Pseudo
//The rest of my javascripts template
...
From my main .js file, I have set up the route:
app.get( '/file.js', function( req, res ) {
//Pseudo code that I would like to achieve
var name = req.query.name;
res.render( 'out_put_javascript_file_from_jade_file.jade', { name: name } );
});
So when a person visits /file.js, the script file will be rendered differently based on the parameter api passed in the URL. The only possible dynamic way I can think of is using Jade, but it doesn't allow pure javascript template. I believe there must be other solutions.
Please excuse my explanation. The problem is somewhat like this: How to generate a pure JavaScript file with Jade
If you want to do something quick and dirty, then you can do something like this (based on your example in the comments).
App init - read the .js template file and cache it:
// this should be async, but hey, not teaching you that part here yet
var fileJs = fs.readFileSync('file.js.template');
File.js:
(function() {
$(window).on('load', function() {
alert('Your api key is API_KEY_CONST');
});
})();
Request:
GET /api/file.js?key=123
Router:
app.get('/api/file.js', function(req, res) {
var key = req.query.key;
var key = fetchKeyFromDBSync(); // just to make it easier here, no async.
var out = fileJs.replace(API_KEY_CONST, key);
res.setHeader('content-type', 'text/javascript');
res.write(out);
res.end();
});
Now, this is really dumb and you should not try it at home, but it simply demonstrates how to do what you wanted.
Edit:
Depending on the file length, you might perform a bit better if you put the chunks of the file into an array, like:
var fileChunks = ['(function(){ blablabla;', 'var myAPIKey=', 'KEY_PLACEHOLDER', '; alert (myAPIKey);', '})()']
So later when you're resolving it with the real API key, you join the file.
fileChunks[2] = '12345';
var responseData = fileChunks.join('');
res.write(responseData);
But your last-accessed api key is then held in an array. Not quite future proof, but it shouls work if you need something quick.

How to access variable on client with express-expose?

I want to set a javascript variable on my index.html page when the page is returned by express.js. I am trying to use the express-expose middleware but I am not sure how to get variable set in the static html page that is rendered.
On the server I have:
app.get('/', function(req, res) {
var user = { name: 'tj' };
res.expose(user, 'user');
res.render(config.rootPath + '/public/index.html');
});
Index html I have
<script>
var myUser = user;
</script>
What I need is myUser to contain the json object user.
Examples I have seen use jade which i am not using.
You need to expose them like this
app.expose('var some = "variable";');
https://github.com/visionmedia/express-expose#raw-javascript
The way you're doing it, they're only available to the templating engine (jade). In which case you'll have to do something like this
script var some = #{variable}

Categories

Resources