I am using this link as reference to build a simple ejs app.
Project structure:
- views
----- partials
---------- head.ejs
----- pages
---------- index.ejs
- package.json
- server.js
server.js:
const express = require('express'),
app = express();
app.set('view engine', 'ejs');
app.use(express.json());
app.use(express.static('public'));
app.get('/', (req, res) => {
res.render('pages/index');
});
head.ejs :
<title>My Awesome Site</title>
index.ejs :
<!DOCTYPE html>
<html lang="en">
<head>
<% include ../partials/head.ejs %> <!-- commenting out this line works -->
</head>
<body class="container">
<main>
<div class="jumbotron text-center header">
<img src="/images/phbc_17.jpg">
<h2 class="page-header">Be Awesome!</h2>
<p>Visit www.myawesomesite.org</p>
</div>
</main>
</body>
</html>
Index renders as expected when I am not including head.ejs partial in it. But, with head.ejs it's rendering only {} in the browser.
What am I doing wrong?
I saw two problems.
You didn't import ejsin your server.ejs file so import is as
const ejs = require('ejs');
Your ejs syntax is a mistake so use below syntax
<%- include ('../partials/head.ejs'); %>
and this need to be inside your body tag
Related
I'm new to node and full stack development and hope I ask this correctly and not carelessly or offensively for your particular level of understanding.
My dev environment is Internet connected, production will not be and I want to use bootstrap.css with node. Apache/httpd is not an option in production.
Testing bootstrap locally has been challenging, the correct directory for the css file is believed correct.
The main directory on CENTOS 7 is myapp, contains app0.js, the node_modules with espress and body-parser and all dependencies, and the views directory which contains grid.ejs.
myapp/
app0.js
node_modules
views/
grid.ejs
public/
bootstrap.css
Here is grid.html (which works on apache):
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap Grid Test</title>
<link rel="stylesheet" type="text/css" href="bootstrap.css">
<style type="text/css">
.pink {
background: yellow;
border: 3px solid red;
</style>
</head>
<body>
<div class="row">
<div class="col-lg-2 pink"><center>2 columns </center></div>
<div class="col-lg-7 pink"><center>7 columns </center></div>
<div class="col-lg-3 pink"><center>3 columns </center></div>
</div>
</body>
</html>
And here is what apache shows for grid.html:
https://imgur.com/VanVZJn "bootstrap with httpd"
However app0.js does not!
So bootstrap.css works (1) when referenced on internet - which I cannot use in production (2) from httpd in my dev environment via http code
but not from an ejs file.
Note: I am able to reach bootstrap from node, because there were 404 errors when it was not reachable showing from the terminal where node was launched. After at least 12 hours trying to understand this, I'm stumped. Sadly with a short timeline to have a solution, I turn to you fine readers!
App0.js
//setup
var express = require('express'),
app = express(),
bodyParser = require('body-parser')
app.set('view engine','ejs');
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.get("/grid", function(req, res, next){
res.render("grid")
});
app.listen(3000,function(){
console.log("serving test demo on port 3000")
});
views/grid.ejs
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap Grid System</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="public/bootstrap.css">
<style type="text/css">
.pink {
background: yellow;
border: 3px solid red;
}
</style>
</head>
<body>
<div class="row">
<div class="col-lg-2 pink"><center>2</center></div>
<div class="col-lg-7 pink"><center>7</center></div>
<div class="col-lg-7 pink"><center>3</center></div>
</div>
</body>
</html>
shown here:
https://imgur.com/ZLOgZKT "bootstrap not working"
You have to define on your app0.js file the public path from where you are going to serve static files. Try the following app0.js file requiring the path module and using express.static after bodyParser.json():
var express = require('express'),
app = express(),
bodyParser = require('body-parser'),
path = require('path')
app.set('view engine','ejs');
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(express.static(path.join(__dirname, 'public')));
app.get("/grid", function(req, res, next){
res.render("grid")
});
app.listen(3000,function(){
console.log("serving test demo on port 3000")
});
And your grid.ejs file link the bootstrap file this way:
<link rel="stylesheet" type="text/css" href="/bootstrap.css">
I have attached my css file to my html file. And then i run and open page using express in node js. However, the css file does not open when i run the webserver through node js.
html(show.ejs)
<html>
<head>
<link rel="stylesheet" type="text/css" href="assets/css/style.css" media="screen" />
</head>
<body>
<h1> Value is <%= detail %></h1>
</body>
</html>
node js
//required npm
var express = require('express');//express 4.*
var path = require('path');
// define app
var app = express();
// set up template engine
app.set('view engine', 'ejs');
//static files
//app.use('/static', express.static('/public')); //not working
app.use('', express.static(path.join(__dirname, 'public'))); //not working
//app.use(express.static(__dirname + '/public')); //not working
//app.use('/public/assets', express.static('public/assets')); //not working
app.get('/show/:id', function (req, res) {
res.render('./panel/show', {
detail: req.params.id ,
});
//port
app.listen(3000);
my project folder
node_modules
views
panel
show.ejs
public
assets
css
style.css
app.js
package.json
By entering <link rel="stylesheet" type="text/css" href="assets/css/style.css" media="screen" /> You are trying to find the assets folder in your out of public directory.
So, when you / it will find public directory which is statically defined in express server.
<html>
<head>
<link type="text/css" href="/assets/css/styles.css" rel="stylesheet">
</head>
<body>
<h1> Value is <%= detail %></h1>
</body>
</html>
Can I include another .ejs file that will wrap the current content?
I want to have a general layout like this:
layout.js:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content">
<!-- I want to "inject" my code here -->
</div>
</body>
</html>
and I want to use this template from another file, like this:
content.ejs
<% inside(layout) ? { %>
content
<% } %>
Can I do something like this?
I'm currently doing this the other way around, I call layout with a parameter include_name but it's a little inconvenient. I would like to call the relevant content.ejs which includes the generic content itself. Is this possible?
Thanks,
From EJS Documentation:
EJS does not specifically support blocks, but layouts can be
implemented by including headers and footers, like so:
<%- include('header') -%>
<h1>
Title
</h1>
<p>
My page
</p>
<%- include('footer') -%>
Although some frameworks have some facilities to deal with problem. for example Express until version 3.x had layout support and for latest versions you could use it as a stand alone npm package: express-partials
With this package in place you define a <%- body %> region in your skeleton template (layout.ejs) and when you call your desired layout (content.ejs), express will render layout.ejs with content.ejs as <%- body %> ( unless you set {layout:false} which then it only renders content.ejs):
layout.ejs
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content">
<%- body %>
</div>
</body>
</html>
content.ejs
content
app.js
var express = require('express')
, partials = require('express-partials')
, app = express();
// load the express-partials middleware
app.use(partials());
app.get('/',function(req,res,next){
res.render('content.ejs')
// -> render layout.ejs with content.ejs as `body`.
})
app.listen(3000);
I am using express with hoganjs templating instead of jade.
When I try to access one of my routes, it wont work though...
In app.js, I have the following (relevant to the route):
var awesome = require('./routes/awesome.js');
app.use('/awesome', awesome);
In the routes/awesome.js file, I have the following:
var express = require('express');
var router = express.Router();
/* GET awesome page. */
router.get('/awesome', function(req, res, next) {
res.render('awesome', { title: "awesome", message: "awesome"});
});
module.exports = router;
And lastly, here is my awesome template (located in ./views/awesome.hjs).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
<meta name="Author" content="{{author}}"/>
<link rel="shortcut icon" href="" />
<!-- Bootstrap CSS-->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<!-- Bootstrap JS -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="jumbotron">
<h1>{{ title }}</h1>
<p>Welcome to {{ title }}, here is your message: {{message}}</p>
</div>
</div>
</div>
</div>
</body>
</html>
I have basically the same code for the index route so why wont this one work too?
In awesome.js change the router path location to /
router.get('/', function(req, res, next) {
res.render('awesome', { title: "awesome", message: "awesome"});
});
Now localhost:3000/awesome should be available.
app.use('/awesome', ...) matches all the routes starting with awesome. Paths specified in router.get('/awesome', ...) acts as sub-paths. The path URL will be localhost:3000/awesome/awesome.
Okay I have a mostly static homepage but I wanted to have partial views that for navigation, footer ect. I'm using ejs and it looks like this:
my controller: home.js
// Dependencies
var express = require('express');
module.exports = {
get: function(req, res) {
app.set('view engine', 'ejs');
var model = {
layout:'home',
};
res.render('home');
}
};
My views directory has nav, home and footer all .ejs
Then the actual html file stripped of text would look as following.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" >
<title>Tom Jones</title>
<!-- CSS -->
<link rel="stylesheet" href="/css/home.css" type="text/css" media="screen" >
</head>
<body>
<%- partial('nav') %>
<!--content part -->
<div id="showcontainer">
<section>
</section>
</div>
<div id="maincontainer">
<section>
</section>
</div>
</body>
</html>
The Problem
When ever I test it out I run into the error partial is not defined. I tried requiring ejs but no success.
As #Pickels said, Partial was removed in 3.x. However, the most recent version of EJS provides a mechanism for including "partials", called "include":
https://github.com/visionmedia/ejs#includes
Includes are relative to the template with the include statement, for example if you have "./views/users.ejs" and "./views/user/show.ejs" you would use <% include user/show %>. The included file(s) are literally included into the template, no IO is performed after compilation, thus local variables are available to these included templates.
The following will work as a replacement for your old partial() function. You'll need to make tweaks elsewhere to support Express 3.x completely, but for the most part this seems to work well (better actually - less code and more performant).
<% include nav.ejs %> <!-- replaces your old <%- partial('nav') %> -->
Now in ejs 3.1.x
<% include('relative_filepath'); %>
Must be replaced by
<%- include('relative_filepath'); %>
Partial was removed in 3.x. It's now up to the templating engine to provide partials.