Routes and scripts in Express (using Jade) - scripts on layout.jade - node.js

I am new to Node, Express, and Jade, and have a question about how to structure my script files.
In my layout I have jquery listed at the bottom. In another file, on another route, I wanted to add a script that uses jquery, so I wanted to add it below the jquery script tag on layout.jade when using that particular route.
layout.jade:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/happy.css')
link(rel='stylesheet', href='/stylesheets/fonts.css')
link(href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600', rel='stylesheet', type='text/css')
link(href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,600', rel='stylesheet', type='text/css')
link(href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet")
link(rel="icon" href="/favicon.png" sizes="16x16" type="image/png")
body
block content
script(src='https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js')
script(src="/javascripts/script.js")
I want this file added to the bottom of my scripts on the layout page when visting the /about route:
script(src="/javascripts/scroll.js")
/routes/about.js:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.render('about');
});
module.exports = router;
from app.js:
app.use('/about', about);

You can use multiple layouts one with the script and one without
you set layouts like this
res.render('about', { layout: 'layoutwithscript.jade' });
Credit to #alessioalex in this post

Related

template layout for PugJs

I used NodeJs with Handlebars and thought about switching to PugJs because some functionality is native - using Handlebars requires some helper functions / partials.
In Handlebars I have to define a layout and pass in the template. In PugJs I created two example routes
First route file:
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('index', {
title: 'Home',
template: 'main'
});
});
module.exports = router;
Second route file:
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('index', {
title: 'Page2',
template: 'pageTwo'
});
});
module.exports = router;
As you can see I always have to render my index file and pass in the desired pug file as a template variable.
index.pug
doctype html
html
include ./header.pug
body
include ./templates/#{template}.pug
header.pug
head
title #{title} template!
main.pug
script(src='./client/main.js')
h1 main content here
pageTwo.pug
p pageTwo
When rendering the pug files I get this error
ENOENT: no such file or directory, open
'...\views\templates\#{template}.pug'
How can I replace #{template} with the correct template variable?
Dynamic template selection isn't a feature of pug, I believe it has something to do with how pug pre-compiles everything into a JavaScript function that stays in-memory inside node.js when it runs. The benefit of that is super-fast page rendering, so we're happy to keep using pug and just work around this.
Speaking of which, you can accomplish what you want to do using conditional logic:
doctype html
html
include ./header.pug
body
if template === 'pageOne'
include ./templates/pageOne.pug
else if template === 'pageTwo'
include ./templates/pageTwo.pug
else
include ./templates/home.pug
You should also look into the extends feature to simplify adding the header into your templates and mixins to resuse code between templates. You might find that these features could provide a better solution to your requirements with some redesign.

Pug: accessing bootstrap from node_modules

I am using pug to output html which I use for later pdf generation with html-pdf.
My controller:
// read file
var source = fs.readFileSync(path.resolve(__dirname, 'templates/pdf.pug'), 'utf-8');
// compile pug template and output html
var template = pug.compile(source);
var html = template(data)
My template
doctype html
html
head
title Merapi Export
link(rel='stylesheet', href='/node_modules/bootstrap/dist/css/bootstrap.min.css')
body
h1 Merapi Export
Is there any way to integrate bootstrap directly from node modules?
Turns out you have to set a base dir to your pug template in the options of html-pdf (used to generate the pdf):
base: 'file:///'+__dirname+'/templates/'
Once this is done you can access bootstrap like this:
link(rel='stylesheet', href='../../../../../../node_modules/bootstrap/dist/css/bootstrap.min.css')
In app.js
app.use(
"/css",
express.static(path.join(_dirname, "node_modules/bootstrap/dist/css"))
)
app.use(
"/js",
express.static(path.join(_dirname, "node_modules/bootstrap/dist/js"))
)
in your pug file
link(rel="stylesheet", href="./css/bootstrap.min.css")
script(src="./js/bootstrap.js", defer)

Set CSS path for Jade layouts

I'd like to set my CSS path in my express application in order to use this one in my jade layouts. However, I don't know how to do, I try to use "app.set('cssPath', __dirname+'/public/admin/css/')" but it doesn't work because I can not use "app.get()" in my external controllers.
My layout _layout.jade :
!!! 5
html(lang='fr')
head
meta(charset='UTF-8')
link(href='admin/css/screen.css', media='screen, projection', rel='stylesheet', type='text/css')
body
.container
h1 Wellcome to Forest Administrator
.space20
block content
.clear.space20
script(type='text/javascript', src='admin/js/jquery.js')
My page edit.jade :
extends ../_layout
block content
.block.half.first
h2 Add a post
And I'd like to use something like :
link(href='+myCssPath+', media='screen, projection', rel='stylesheet', type='text/css')
Not sure if I get what you want to do but You can use
res.locals.cssPath = 'string with the path';
And cssPath will be available in your template.
Besides that you don't need __dirname+'/public/. Part because when the page is rendered for the browser /public/ will be /
[edit] If you want to have that variable available in all you routes, but declaring it just once, you can create a small middleware like
var express = require('express');
var app = express();
var app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
// .. and your other tipical configuration
//this small middleware for variables that must available in all paths
app.use(function(req, res, next) {
res.locals.cssPath = 'path to the css directory';
next();
});
});
//From here your typical route declarations
app.get('/', function(req, res) { res.render('someView'); });

how do i compile multiple jade files

let's start off with the following 4 jade files.
layout.jade
html
head
block cms_head
body
block cms_body
home_page.jade
extends layout
block append cms_head
title home page
block append cms_body
p superman ate so many different apples
plugin_a.jade
block append cms_body
p i got plugged in... genius
plugin_for_jquery.jade
block append cms_head
script(src="/jquery-1.8.3.js")
so i can easily render the home page by doing:
app.get("/", function(req, res){
res.render("home_page");
});
which is fantastic, however in order to allow for plugability in my app, i would like to allow their views to take advantage of existing templates, and append/prepend/replace content to whatever the plugin needs to show.
what i am trying to do is render home_page.jade, then render plugin_a.jade and plugin_for_jquery.jade ... the basic idea is there can be a variable number of plugins, and each plugin adding it's own content to the view.
I tried this (obviously it didn't work)
for plugin in plugins
include= plugin.name
So any ideas on how i can do that?
as far as i know there is no possability in jade to readout the directory
but using node:
var fs = require("fs");
app.get("/", function(req, res){
fs.readdir(DIR_OF_PLUGINS, function(err, list){
res.render("home_page", {"list": list});
});
});
and in homepage.jade
- for(plugin in list)
include = plugin
btw: you should build a router and a functions document with something like
//router.js // or app.js
var funct = require("routes/functions")
app.get('/', funct.home);
//functions.js
exports.home = function(req, res){

Express - Passing data to all routes

Hi is there a 'express' specific way to make some global app data available to all my routes?
Or is it a case of just using an module.exports statement?
Any pointers more than welcome.
Node noob - btw
You can set a global object that is also available in your layout
app.js
app.configure(function(){
app.set('view options', {pageTitle: ''});
});
app.get('/',function(request, response){
response.app.settings['view options'].pageTitle = 'Hello World';
response.render('home');
});
layout.jade
!!!
html
head
title= pageTitle
body!= body
You can use app.set() in the setup portion of your app to make it available to each request. The app object is available via req.app in your routes.
Personally, I like to do an app.set('name', obj); in the setup and in the routes I access it via req.app.settings.name.
You could also use a dynamic helper to pass data to all views.
app.js
// Dynamic Helpers
app.dynamicHelpers({
appSettings: function(req, res){
return {name:"My App", version:"0.1"};
}
});
Now on your views you can use it like this (I used ejs on this example but it should work with jade or any other view engine):
view.ejs
<%= appSettings.name %>
<%= appSettings.version %>
Hope this helps.

Resources