Server Side rendering in mongo with dust - node.js

Is it possible to fetch data from MongoDB and render a html template on the server side itself for a node-js project?
As of now in my serverside js file I've done the following.
//Failing array will be populated by a db.find later on.
var failing = [
{ name: "Pop" },
{ name: "BOB" }
];
/*Now i have to send a mail from the server for which I'm using nodemailer.
Where do i store the template ? This is what I've done in the same file */
var template = "<body>{#failing} <p>{.name}</p> {/failing}</body>"
// Add this as the body of the mail and send it.
I'm not sure how to render the data and how to get it displayed. I'm aware storing the template in the variable isn't right but I'm not sure what else to do.

If your template is that short, you can store it in a variable without problem. Obviously, you can store it in a file also.
Let's say you decide to store it in a file index.dust:
<body>{#failing} <p>{.name}</p> {/failing}</body>
Now, in your node controller you need to load the file and generate the html content from it:
const fs = require('fs');
const dust = require('dustjs-linkedin');
// Read the template
var src = fs.readFileSync('<rest_of_path>/index.dust', 'utf8');
// Compile and load it. Note that we give it the index name.
var compiled = dust.compile(src, 'index');
dust.loadSource(compiled);
// Render the template with the context. Take into account that this is
// an async function
dust.render('index', { failing: failing }, function(err, html) {
// In html you have the generated html.
console.log(html);
});
Check the documentation in order not to have to compile the template every time you have to use it.

Related

How to receive data passed by the server on client side

I want to pass data from the server to the client (GET request), when I was using pug I did it with
// Server:
res.render('pageToRender', { variableToPass: value })
And on the client side I just referred to it with variableToPass. How can I do this with html and javascript though? I cannot find out...
It is possible via hack by inlining string value of javascript variable in a template
Here the example:
template.pug
<p>Forbes's Pug source code!</p>
<script>
var variableToPass = JSON.parse('#{variableToPass}')
console.log(variableToPass)
</script>
server.js
res.render('pageToRender', { variableToPass: JSON.stringify(value) })

Passing objects between nodejs and jade

I have the following code in my server.js
var cddata = [];
body.rows.forEach(function(doc) {
cddata.push([{id: doc.id, name: doc.key, text:doc.value.Time, group: 1}]);
});
response.render('timeline', {cddata: JSON.stringify(cddata)});
and I have the following in my Jade view file
script(src='vis/dist/vis.js')
link(rel="stylesheet", href="vis/dist/vis.css", type="text/css")
script.
//alert(cddata);
var options = {};
var data = new vis.DataSet(cddata);
var container = document.getElementById('visualization');
new vis.Timeline(container, data, options);
However, nothing related to the chart is rendered. I presume the object is not correctly passed to the jade file. Please help!
Also, is there a way to verify the incoming object in Jade? Alerts dont seem to work.
thanks
The <script> in your jade is a browser side script so won't be able to access variables in the templates generation scope. You'll need to output your data as JSON and read it in using browser side JavaScript, something like this:
script(src='vis/dist/vis.js')
link(rel="stylesheet", href="vis/dist/vis.css", type="text/css")
script.
var chartData = JSON.parse('#{cddata}')
var options = {};
var data = new vis.DataSet(chartData);
var container = document.getElementById('visualization');
new vis.Timeline(container, data, options);
After much deliberation, the following worked to pass object from node server to client side server scripting on Jade file.
on the server.js, where dbdata is an array of JSON objects
response.render('timeline', {dbdata:dbdata});
On the jade file,
script.
var chartData = !{JSON.stringify(dbdata)};
Thanks,

how to retrieve data from mongodb to javascript

I am currently new to nodejs and mongodb, so please forgive me for this newbie type of question.
What I want is to pass data from my mongodb file to my js file which is running my mini-game.
What I am doing right now is using jsp tags to retrieve data from my mongodb (I am following this practice from a project that I have seen, but he is doing this on his html file which is working out well for him. for my case I was just trying my luck)
var win = <%= user.win %>;
var lose = <%= user.lose %>;
var draw = <%= user.draw %>;
How do I retrieve the data I had from my mongodb to javascript?
If you have an Node.JS with Express application, there are many ways to do it. If you're using a template engine, you could render the data as part of the HTML page in a script block (or render it directly as HTML, avoiding script). Or, you might want to use an Ajax style request and send back the data to the client.
app.get('/api/users/:id', function(req, res) {
Users.findOne({ _id : req.params.id }, function(error, user) {
if (error || !user) {
res.send({ error: error });
} else {
res.send(user);
}
});
});
Once you've got that ready, you could use jQuery's ajax function for example to call the web service.
$.ajax({
url: "api/users/" + userId,
}).done(function(user) {
// here you have a complete user object that you can use
});
The code you posted makes me think that you're using a template engine though. I would expect that there is a render method with your template HTML file:
res.render('homepage', user);
Then, in the HTML:
<script>
var win = <%= win %>;
var lose = <%= lose %>;
var draw = <%= draw %>;
</script>
As the user object is the object with current context (as it was passed as the parameter in my example above), you can just directly refer to the properties of the user object directly (just win rather than user.win).

How can I bootstrap models from express js into backbone at page load?

I have some data in a mongodb database and want to pass it to a backbone collection when I load the home page. One way of doing this would be to set up a node route like this:
exports.index = function(req, res){
db.users.find(function(err, docs) {
var docs_string = JSON.stringify(docs);
res.send(docs_string);
};
};
But this won't work because it won't render my jade template that pulls in the backbone code, it simply shows the JSON in plain text.
Alternatively, I could render my jade template passing in the data as a variable to jade:
exports.index = function(req, res){
db.users.find(function(err, docs) {
var docs_string = JSON.stringify(docs);
res.render('index', {
title: "Data",
docs_string: docs_string
})
});
};
Then in the jade template, have a script like this to add the users to my user collection:
script
var docs = !{docs_string};
var users = new app.Users();
_.each(docs, function(doc) {
var user = new app.User(doc);
users.add(user);
})
But this seems wrong, since I don't really want to pass the data to the jade template, I want to pass it to a backbone collection. Also, with this solution I don't know how to then include an underscore template (on the backbone side of things) into the page rendered by jade on the server side.
What is the standard way of passing data from a node server to a backbone collection?
Assuming your data is an object, you should convert it to string using JSON.stringify() and then insert in a page inside script tag, so your resulting HTML looks like this (I don't use Jade):
<script>
var data = {...}; // in template instead of {...} here should be the instruction to insert your json string
</script>
Then when the page loads, your script will be executed and the data will be available as a global variable in the browser so you can initialise backbone collection using it. This all is a good idea only to bootstrap your data on the first page load (to avoid extra request) and then use API to request data for this and other pages.
Check out Steamer, a tiny node / express module made for this exact purpose.
https://github.com/rotundasoftware/steamer

Render Image Stored in Mongo (GridFS) with Node + Jade + Express

I have a small .png file stored in Mongo using GridFS. I would like to display the image in my web browser using Node + Express + Jade. I can retrieve the image fine e.g.:
FileRepository.prototype.getFile = function(callback,id) {
this.gs = new GridStore(this.db,id, 'r');
this.gs.open(callback);
};
but I don't know how to render it using the Jade View Engine. There doesn't seem to be any
information in the documentation.
Can anyone point me in the right direction?
Thanks!
I figured this out (thanks Timothy!). The problem was my understanding of all these technologies and how they fit together. For anyone else who's interested in displaying images from MongoDB GridFS using Node, Express and Jade ...
My Document in MongoDB has a reference to the Image stored in GridFS which is an ObjectId stored as
a string. e.g. MyEntity {ImageId:'4f6d39ab519b481eb4a5cf52'} <-- NB: String representation of ObjectId. The reason I stored it as a string was because storing the ObjectId was giving me a pain
in the Routing as it was rendering as binary and I couldn't figure out how to fix this. (Maybe someone can help here?). Anyway, the solution I have is below:
FileRepository - Retrieve the image from GridFS, I pass in a String Id, which I then convert to
a BSON ObjectId (you can also get the file by file name):
FileRepository.prototype.getFile = function(callback,id) {
var gs = new GridStore(this.db,new ObjectID(id), 'r');
gs.open(function(err,gs){
gs.read(callback);
});
};
Jade Template - Render the HTML Markup:
img(src='/data/#{myentity.ImageId}')
App.JS file - Routing (using Express) I setup the '/data/:imgtag' route for dynamic images:
app.get('/data/:imgtag', function(req, res) {
fileRepository.getFile( function(error,data) {
res.writeHead('200', {'Content-Type': 'image/png'});
res.end(data,'binary');
}, req.params.imgtag );
});
And that did the job. Any questions let me know :)
I'm a little confused about what you're trying to do here, as Jade is a condesed markup language for text output (such as HTML), not binary content.
Since you're using Jade you probably have something like this:
app.get/'images/:imgtag', function(req, res) {
res.render('image', {imgtag: req.params.imgtag);
});
So try this:
app.get/'images/:imgtag', function(req, res) {
filerep.getFile( function(imgdata) {
res.header({'Content_type': 'image/jpeg'})
res.end(imgdata);
}, req.params.imgtag );
});
That will send the raw file as a response to the HTTP request with the correct mime type. If you want to use Jade to deliver a template (such as an image popup) you could use a different route for the popup or even use a data: uri and encode the image data in the page.

Resources