Accessing jQuery object in JADE - node.js

During login, I save the userId in a jQuery cookie, so that I can access it by $.cookie('userId').
Now that I am trying to access it from Jade, as,
- if ($.cookie('userId') === userId)
I get an error
$ is not defined
How can I access the cookie ?
My code:
- if (($.cookie('userId')) === userId)
input(type='submit', value='Move')
else
input(type='submit', disabled, value='Move'')

You seem to misunderstand concepts. Let me give you a lecture. ;)
Basics. Cookie is stored on the client-side. So using jQuery $.cookie('userId') will retrieve it when this script is run on the client-side.
But here you use JADE templating engine on server-side. So you didn't even send the page to the client-side yet. So what cookie do you want to retrieve? There is no cookie, because you are at the server.
There's more. Running $.cookie('userId') throws the error, because you are on the server-side. There is no $ object. And there cannot be, because you cannot use jQuery on server-side (well, actually you can, but this is irrelevant at the moment). Did you define $ object in your route system? Or did you define helper $? I don't think so.
Express+JADE tutorial. Now let me give you a short tutorial. Say you have a view (in app.js)
app.get('/', function(req, res){
res.render('index.jade', { code: 500 });
});
Now in index.jade you can use code as a variable. So you can write your index.jade for example like this:
// some code
- if (code == 500)
input(type='submit', disabledm, value='Move')
- else
input(type='submit', value='Move')
// some code
and now it will work! You may also use JavaScript functions in template if you predefine them. For example (in your app.js)
app.helpers({
positive: function(no) { return no > 0; }
});
then in index.jade template you can use
- if (positive(-13))
input(type="submit")
and even combine these two concepts
- if (positive(code))
// do some stuff
To cookie or not to cookie. If you really need to use cookies (and you shouldn't except for sessions or CSRF for example) then you need to use client-side JavaScript. This means that you need to add (after jQuery)
script(src='my-path/my-script.js')
to the index.jade file and write my-script.js like this
$(document).ready(function() {
if ($.cookie('userId') == userId) {
// do something like append input to some holder
}
});
But there are several problems with that solution. First: what is userId (second part of equality)? You need to predefine it in your index.jade. For example using
script
var userId = #{ user.id };
and adding user object in your route. Second: cookies are local variables. Setting them requires additional server code which I do not thing you would like. This makes maintaining the app harder. And finally: storing a user's id in a cookie seems to be pointless. The final user don't even have to know it's own id. The server needs to know! Sessions system comes handy here.
Final note. The code you wrote shows us that you cannot distinguish between server-side and client-side JavaScript. The solution to your problem is to learn, learn and learn. Read tutorials and everything about JADE, Express and Node.js.

What #freakish said is right. You're trying server side vs. client side.
If the cookie is set you should be able to access it on server like so
app.use(express.cookieParser());
app.get('/', function(req, res){
// index is jade template
// local variable on jade template holds cookie value
// use req.cookies.userid
res.render('index', { userid: req.cookies.userid });
});

Related

Fastify point-of-view local variables

I am switching from Express.js to Fastify. I need to do it quickly, so using only API is impossible yet. Haven't written React app.
My problem is: I am using point-of-view and I don't know how to pass local variable to all requests. In express there something like
app.use(function (req, res, next)
{
res.local.new_notifications = 50;
})
and I can get it in template engine on every page like
<%= new_notifications %>
Is there something like this in Fastify + point-of-view?
You can, I am not sure if it is a new implementation or not since you asked a solution more than 1 year ago, this is for future viewers.
You simple have to add a .locals object and attach to it anything you want available with your engine.
This is from the documentation:
If you want to provide data, which will be depended on by a request and available in all views, you have to add property locals to reply object, like in the example below:
fastify.addHook('preHandler', function (request, reply, done) {
reply.locals = {
text: getTextFromRequest(request) // it will be available in all views
}
done()
})
Be sure to create the object with the assignment {} since locals its not defined!

Using variables amidst html in node.js

Here's the deal:
I already have node.js server which communicates with a database;
I need to create a webpage for people to access and check leader-boards
from the database (the server queries the database to show the users
with top 10 scores);
The example below shows a server responding with html;
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<!doctype html>\n<html lang="en">\n' +
'<head>\n<meta charset="utf-8">\n<title>Test web page on node.js</title>\n' +
'<style type="text/css">* {font-family:arial, sans-serif;}</style>\n' +
'</head>\n<body>\n<h1>Euro 2012 teams</h1>\n' +
'<div id="content"><p>The teams in Group D for Euro 2012 are:</p><ul><li>England</li><li>France</li><li>Sweden</li><li>Ukraine</li></ul></div>' +
'\n</body>\n</html>');
res.end();
}).listen(8888, 'address');
console.log('Server running at http://address:8888');
How would I go about to do something similar but instead the list would be the result of a query to the database?
Note:
I already know how to query, I only need to know how to have the results shows in the HTML code above
Thanks in advance
Most modern web applications solve this problem by using a template engine. You asked for something similar, and this is likely the better way to go about it.
A template allows you to have a file or simply a string with variable placeholders and then you can pass a model (in this case, your return value from the database) to the template, render it, and send that to the client.
Depending on the database you're using, you will have to likely start making your queries using Node.js's asynchronous patterns. Generally when you make a query in Node.js you will follow a pattern similar to
...
db.create({"name" : "rawr"},
function(err, data) {
if (err) {
// handle error
}
// build your template
// res.send the compiled HTML
});
...
Of course this all depends on the database that you're using, but generally it will look something like that. If you're comfortable with HTML I recommend looking into Handlebars.js but also loking at the link provided above for a few more and find one you like. Without a few more details such as constraints or database being used, this is about as much as I can say.

Get return value of `include` in jade template

What I basically try to accomplish is to re-use jade partials/templates when getting data through a socket connection. Non working example:
socket.on('company_created', function(company) {
var html = include _company;
$('#companies ul').append(html);
});
Normally I had to create a new li and set the content like so (which is working as expected):
$('#companies ul').append($('<li>').text(company.name));
This is okay for a simple list, but if I had complexer list and stuff, this could get messy pretty quick, plus I had to write plain HTML again, so I figured re-using my already existing jade templates with all their goodness would be awesome, but had not luck, yet.
Any clue?
PS: Please do not tell my to use Ember, Backbone, Derby, Meteor, Angular or whatsoever.
Thanks in advance!
You can compile your jade sources to JS with jade.compile. Then include these sources in the client-side javascript, include jade's runtime.min.js, and refer to your jade templates as to normal JS functions in your client-side code.
For example,
server.js
app.get('/templates/:template.js', function (req, res) {
var template = req.params.template;
response.end([
"window.templates = window.templates || {};",
"window.templates[\"" + template + "\"] = " + jade.compile(template + ".jade", { client: true; });
].join("\r\n"));
});
client.js
$(function() { $("#placeholder").html(window.templates["content"]({user: "Daniel" })); });
content.jade
h1: Hello #{user}!
index.jade
!!!
html
head
script(src='/lib/jquery/jquery.js')
script(src='/lib/jade/runtime.min.js')
script(src='/templates/content.js')
script(src='/scripts/client.js')
body
#placeholder
Note that the code above might be syntactically incorrect and is provided solely to illustrate the idea.
we have a build step that compiles them to functions sort of like penartur mentioned. I dont use extend or include (which dont work on the client anyway ATM), but personally I find we have absolutely no need for that on the client at all since the DOM provides all the separation we need.

How do I pass variables from Connect's middleware into app.get-action?

I would like to create kind of a before filter which allows me to make the current user available in all actions. The followint approach works well and I didn't even need to declare a global variable:
app.use(function(req, res, next){
if(req.session.user_id){
/* Get user from database
and share it in a variable
that can be accessed frooom ...
*/
User.find({ /* ... */ }, function(err, users){
if(users.length == 1){
req.current_user = users[0];
}
next();
});
}
else{
next();
}
});
app.get('/', function(req, res){
// ... here!!
console.log(req.current_user);
res.render('index', {
current_user: req.current_user,
});
});
But I'm still unsure if it is okay to manipulate req because I don't know if it's right to change something that's not owned by me? Is there a better way to do this?
Go right ahead and tack on properties to req! When I was first starting out with Node.js and JavaScript, this felt very odd to me too (coming from a predominately C++ background). It is, however, quite natural given JavaScript's prototypical object model. After you get comfortable with it, you'll realize that you can do powerful things in succinct code.
I'm the developer of Passport (mentioned by the previous commenter). If you are planning on developing middleware that can be reused across apps, my advice is to pay a bit of attention to how you name the properties that you add to req or res, to avoid any potential conflict with other middleware in the same application.
For example, Passport sets the user at req.user, but gives an option to change that (so an app can say set it at req.currentUser, for example.). Internal, private variables are attached to a req._passport property.
It's a common approach to extend req with session or user object
For example see these examples:
Passport, a popular authentication library https://github.com/jaredhanson/passport/blob/master/lib/passport/strategies/session.js
Connect middleware for cookie session https://github.com/senchalabs/connect/blob/master/lib/middleware/cookieSession.js

Render template to variable in expressjs

Is there a way to render template to a variable instead to output?
res.render('list.ejs', {
posts: posts
});
something like this
var list = render('list.ejs', {
posts: posts
});
The easiest way to do that is to pass a callback to res.render, in your example:
res.render('list.ejs', {posts: posts}, function(err, list){
//
});
But if you want to render partial templates in order to include them in another template you definitely should have a look at view partials.
I am quite a newbie on express.js, anyway I am not sure you can access the rendered string that way, although if you look at express' "view.js" source on github (here) you see that it's accepting a callback as second argument, if that may help: you may access the rendered string there.
Otherwise, I think it's quite easy to patch the code to add a method returning the rendered string without sending it: on line #399 you have the very call that gives the string you are looking for.
This wasn't the question originally asked, but based on comments from the OP and others, it seems like the goal is to render a partial via json (jsonp), which is something I just had to do.
It's pretty easy:
app.get('/header', function (req, res)
{
res.render('partials/header', { session: req.session, layout: null }, function (err, output)
{
res.jsonp({ html: output });
});
});
Note: In my case, the header partial required the session, and my template library (express-hbs) needed layout: null to render the partial without using the default layout.
You can then call this from Javascript code in the client like any other JSONP endpoint.

Resources