Nodejs and Jade rendered my submit button as a text field - node.js

In a nodejs application, with Jade templating, I can't manage to render a submit button.
This is my app.js code :
var express = require('express');
var app = express();
app.get('/todo', function(req,res){
res.set({
"Content-Type" : "text/html",
"charset" : "utf-8"
});
res.render('todo_list.jade', {list : [
"Lire un livre", "Jouer de la musique", "Apprendre la programmation", "Jouer au dé pipé !"
]});
});
// app.post('/todo/ajouter', function(req, res){
//
// });
//
// app.post('/todo/supprimer/:id', function(req, res){
//
// });
app.listen(8080);
This is my view/todo_list.jade :
doctype html
head
title Ma todo list
body
h1 Ma todo list
ul
- for (var i = 0; i < list.length; i++)
li #{list[i]}
form
label(for=new_task) Que dois-je faire ?
input(type=text, id=new_task, name=new_task, size=15)
input(type=submit, value=Ajouter)
So why I am getting two text fields instead of a text field and a button ?
In my application root folder, I've installed (with a package.json file) express ~4.3.2, cookie-session ~1.0.2, body ~4.4.2, and jade ~1.3.1

The cause of your problem is that you are not properly assigning attributes to your tags. In Jade, attribute values are evaluated as JavaScript expressions. This means that leaving your attribute values unquoted will use the variable's value rather that the literal value.
Here is the fixed Jade template that will give you the desired output:
doctype html
head
title Ma todo list
body
h1 Ma todo list
ul
- for (var i = 0; i < list.length; i++)
li #{list[i]}
form
label(for='new_task') Que dois-je faire ?
input(type='text', id='new_task', name='new_task', size=15)
input(type='submit', value='Ajouter')

Related

Why the li tag not getting the value of loop variable?

I am trying to loop through the object that is coming from app.js. I am using each loop in PUG/JADE, so that I can use its value to print some values. But the li is not getting the value of loop variable
Note : I am getting 'post.title' and 'post.body' below 4 times because, it's coming from the mongo database and I did exactly 4 entries in the database. Plus this also means that object is correctly coming to the index page, but li is not getting the value of loop variable.
Output I am getting
. = post.title
. = post.body
. = post.title
. = post.body
. = post.title
. = post.body
. = post.title
. = post.body
What I want
Title of the post
body of the post
Title of another post
Body of another post
and so on....
My Code
---- index.pug ----
block content
ul
each post in posts
li = post.title
li = post.body
---- app.js ----
let Post = require('./models/post');
app.get('/', function(req, res){
Post.find({}, function(err, posts){
if(err){
console.log(err);
} else {
res.render('index', {
title:'Posts',
posts: posts
});
}
});
});
What Else I tried
I made a constant array just above the loop to check and iterated through that array. But it gave me the same result as
. = name
. = name
. = name
don't know why. The code for that is below.
block content
- const names = ["Sami", "Abeer", "Hassaan"];
ul.list-group
each name in names
li = name
Remove the space between li =, so you get li= name. The space indicates that the equal sign should be content of the tag.
Full example of your index.pug:
block content
ul
each post in posts
li= post.title
li= post.body

Use a variable in a Jade include

I'm working with Jade and Express and I would like to use a variable in my include statement. For example:
app.js
app.get('/admin', function (req, res) {
var Admin = require('./routes/admin/app').Admin;
res.render(Admin.view, {
title: 'Admin',
page: 'admin'
});
});
layout.jade
- var templates = page + '/templates/'
include templates
When I do this I get the error EBADF, Bad file descriptor 'templates.jade'
I even tried
include #{templates}
to no avail.
AFAIK JADE does not support dynamic including. What I suggest is to "include" outside the template, i.e.
app.js
app.get('/admin', function (req, res) {
var Admin = require('./routes/admin/app').Admin;
var page = 'admin';
var templates = page + '/templates/';
// render template and store the result in html variable
res.render(templates, function(err, html) {
res.render(Admin.view, {
title: 'Admin',
page: page,
html: html
});
});
});
layout.jade
|!{ html }
this also works:
//controller
var jade = require('jade');
res.render('show', {templateRender: jade.renderFile});
//template
!= templateRender('my/path/'+dynamic+'.jade', options)
This probably will not increase the performance that you would expect from using the 'view cache' setting (it's on by default in NODE_ENV === 'production'). Or even break the app (e.g. if files are not available on the hard drive while deploying new code). Also trying to use this trick in a client-side or isomorphic app will not work because the template can not be compiled.
Found this page googling for the same question, but in a different context, so thought I'd put my solution (read: workaround) here for posterity:
I wanted to surround my include with more context pulled from the variable, e.g. (simplified):
- var templates = page + '/templates/'
- var headid = page + 'head'
- var imgsrc = '/images/' + page
div(id=headid)
h1 #{page}
img(src=imgsrc)
div(id=page)
include templates
Since that doesn't work (Jade doesn't support dynamic includes, as noted by freakish), I hybridized with a mixin:
(Edit– a little more elegant than my previous workaround:)
mixin page1
include page1/templates
mixin page2
include page2/templates
...
- for (var i = 0; i < 3; i++)
- var page = 'page' + i
- var headid = page + 'head'
- var imgsrc = '/images/' + page
div(id=headid)
h1 #{page}
img(src=imgsrc)
div(id=page)
+page
My previous answer:
mixin templates(page)
- var headid = page + 'head'
- var imgsrc = '/images/' + page
div(id=headid)
h1 #{page}
img(src=imgsrc)
+templates('page1')
#page1
include page1/templates/
+templates('page2')
#page2
include page2/templates/
...
It's not elegant, and it won't work if you need to include more than a few things this way, but at least part of the Jade is dynamic.
Why do not use jade inheritance?
Render what you want at middleware level:
res.render('templates/' + template_name + '.jade')
Write common common.jade:
h1 This is a page
.container
block sublevel
h2 Default content
Then write file that extends common.jade:
extends common.jade
block sublevel
h2 Some things are here
It's 2019 and using variables in Pug (previously Jade) mixins has become simple.
When creating your mixin, you can give it parameters as per value(s) you're expecting to pass to the mixin. You can access any nested values using dot notation.
mixinFile.pug:
mixin myMixin(parameter1, parameter2, parameter3)
h2.MyHeading #{parameter1}
p.MyParagraph #{parameter2.myVariable}
.MyBox(id= parameter3.id)
index.pug:
include mixinFile
block content
+MyMixin(variable1, variable2, variable3)
You can read more in the official Pug documentation on Mixins.

Jade dynamic data

Using node.js I am passing some variables to jade view:
res.render('index', {
locals: {
name: user.name,
hashpassword: JSON.stringify(user.hashPass),
languages: JSON.stringify(langs)}
});
In jade file I have:
body
#heading
h1 nodechat
label !{locals.languages} // working - printing whole json string
#content
- var laangs = !{locals.languages} //not working here!
//SyntaxError: Unexpected token .
- each item in laangs
label= item.EnglishName
The problem is that I cannot pass locals.languages to a variable in jade file. If I assign it to a single html element (like label), it's working, but when I try with var = that doesn't work.
What may be the problem?
See my change below...
body
#heading
h1 nodechat
label !{locals.languages} // working - printing whole json string
#content
//- Do it like this...You're already in JavaScript land after the -
- var laangs = locals.languages
- each item in laangs
label= item.EnglishName
Change !{locals.languages} into locals.languages

Yui hide and show nodes

in this example its replace the div container with other element but its get the other element from the yui function how can i make same example but with replace two divs in the html
HTML
<div id="demo">
<p><em>Click me.</em></p>
</div>
Script
YUI({ filter: 'raw' }).use("node", function(Y) {
var node = Y.one('#demo p');
var onClick = function(e) {
// e.target === node || #demo p em
var tag = e.target.get('parentNode.tagName');
// e.currentTarget === node
e.currentTarget.one('em').setContent('I am a child of ' + tag + '.');
};
node.on('click', onClick);
});
You mean, You'd like to replace another div or select another div?
In this example, em is selected and then its content is changed by setContent( "your new content" )
You can just select the e.currentTarget (the node or #demo p div) and setHTML() and build your div inside like string for example <div>content<div>, this is just one out of millions of ways to accomplish this.
have a look to this: http://www.jsrosettastone.com/

express+jade: provided local variable is undefined in view (node.js + express + jade)

I'm implementing a webapp using node.js and express, using the jade template engine.
Templates render fine, and can access helpers and dynamic helpers, but not local variables other than the "body" local variable, which is provided by express and is available and defined in my layout.jade.
This is some of the code:
app.set ('view engine', 'jade');
app.get ("/test", function (req, res) {
res.render ('test', {
locals: { name: "jake" }
});
});
and this is test.jade:
p hello
=name
when I remove the second line (referencing name), the template renders correctly, showing the word "hello" in the web page. When I include the =name, it throws a ReferenceError:
500 ReferenceError: Jade:2 NaN. 'p hello' NaN. '=name' name is not defined
NaN. 'p hello'
NaN. '=name'
I believe I'm following the jade and express examples exactly with respect to local variables. Am I doing something wrong, or could this be a bug in express or jade?
app.set ('view engine', 'jade');
app.get ("/test", function (req, res) {
res.render ('test', {
name: "jake"
});
});
you can do it like this.
Rather than =, you can use #{variable-name}. Here is an example of how I'm using it:
This will render a page, with a menu for navigation. Passing the page title in each time the page is loaded, ofcourse you will need to create an app.get function for each page.
App.js
var navigation = {
home : {
uri : "/",
url : "index",
title : "Home"
},
lab : {
uri : "/lab",
url : "lab",
title : "Lab"
},
profile : {
uri : "/profile",
url : "profile",
title : "Profile"
},
timetable : {
uri : "/timetable",
url : "timetable",
title : "Timetable"
}
}
app.get(navigation.profile.uri, function(req, res){ //Profile
res.render(navigation.profile.url, {
title: navigation.profile.title,
navigation: navigation
});
});
profile.jade
section#page-content
h1#page-title #{title}
p Welcome to #{title}
layout.jade
!!! 5
html
head
title= title
link(rel='stylesheet', href='/stylesheets/reset.css')
link(rel='stylesheet', href='/stylesheets/style.css')
body
header#site-header
nav#site-navigation
!= partial("partials/navigation")
section!= body
footer#page-footer
I think the error is sometime caused due to the request by the browser for favicon.ico.
Try adding these lines to the layout.jade head to link the icon
link(rel='icon', href='/images/siteicon.png')
This removed the same error that I was getting

Resources