How ejs template is loaded on browser? How frontend interact with backend? - html

Working on frontend and backend using NodeJs for server side and ejs template for frontend. Came across a feature while using ejs scriplets to display data send from server while loading page.
Used <%console.log()%> over ejs, thought this log will be seen on inspect element logs, however got message over server terminal. How did this information is send over to server without any form submit or API call?
Server app.js:
/*jshint multistr: true, node: true, esversion: 6, undef: true, unused: true, varstmt: true*/
"use strict";
// NPM Modules
const express = require('express'),
path = require('path');
const app = express();
// Setup views directory, file type and public filder.
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.render('index', {message:'Welcome'});
});
const port = process.env.PORT || 3000;
console.log('server listening at http://127.0.0.1 over port: ', port);
app.listen(port);
EJS template index.ejs:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<!-- All these CSS files are in plublic directory, as we had made all the content of public directory available for anyone from app.js -->
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="/css/app.css" />
<link rel="shortcut icon" href="logo.jpg" />
<title>Sign-Up/Login Form</title>
</head>
<body>
<%console.log(message)%>
<%=message%>
<%console.log("anything")%>
</body>
</html>
How can all the <%console.log()%> are send over server terminal and <%=message%> is displayed over browser. Even <%console.log("anything")%> is displayed over server terminal even though this has nothing to do with server. How ejs scriplets communicate with server and not browser?
Had anyone else tried this before or observed it.

Your question is about how ejs templates work. This is an answer for that question. I think you might also have something wonky going on with your express setup causing you problems.
EJS is a server-side rendering system. It's job is done before the html is sent to the client, so it has nothing to do with the browser.
The scriptlets inside <% %> run on the server to insert content into the template before sending to the client.
If you want to print something out on the browser console, don't put it in a scriptlet, just put it into a <script> tag, like this:
<script>
console.log("foo");
</script>
If you want the browser console to print something generated by the server, you could use ejs to put the value of message into what it generates:
<script>
console.log("<%=message%>");
</script>
The server will put the value of message into a console.log() statement that gets delivered to the browser.
This example prints "Wellcomes" to the browser console:
server:
const bodyParser = require('body-parser'),
express = require('express'),
path = require('path');
const app = express();
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.render('index', { message: 'Wellcomes' });
});
const port = process.env.PORT || 3000;
const listener = app.listen(port, function() {
console.log('platform listening on', listener.address().port);
});
index.ejs:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Sign-Up/Login Form</title>
</head>
<body>
<script>
console.log("<%=message %>");
</script>
</body>
</html>
If you show page source in your browser, you should see:
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title>Sign-Up/Login Form</title>
</head>
<body>
<script>
console.log("Wellcomes");
</script>
</body>
</html>

Related

Express and ejs

I've recently started learning EJS and Express.
Here is my app.js file :
let app = express();
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('index');
});
app.get('/fallinlovewith/:thing',(req,res)=>{
var name = req.params.thing;
res.render('love',{name:name});
});
app.listen(3000, () => console.log('Example app listening on port 3000!'));
And here are my index.ejs and love.ejs files :
index.ejs :
<h1>This is succesful !</h1>
love.ejs :
<h1>You fell in love with :</h1>
<p>This is from love.ejs folder</p>
My code is able to render index.ejs file but not love.ejs .
love.ejs shows the following text instead of the normal heading and paragraph.
This is what is being displayed at http://localhost:3000/fallinlovewith/dipti
I don't know what these "question mark" symbols denote.
I'm stuck here . Can someone help ?
Try specifying the language and the charset in the html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
...

How to link css file with ejs?

In my directory I have created a public folder in which I have put another folder named css in which is located styles.css. In another folder in my directory named views I have put my ejs file, with which I want to link styles.css like this:
<link rel="stylesheet" type="css/text" href="css/styles.css">
However this does not work.
I dont even get an error in my browsers console.
If you are using npm and Express, we need to set up a public folder for the static content (like your css file):
1) In your root folder, create a folder called 'public', then another one inside called 'css' and place your styles.ccs file in there.
2) In your JS application file (e.g. app.js), we need to have something like this:
//jshint esversion:6
const express = require('express');
const ejs = require("ejs");
const app = express();
app.set('view engine', 'ejs');
app.use(express.static("public"));
app.get('/', (req, res) => {
res.render('index', { foo: 'FOO' });
});
3) In your root folder, create a folder called 'views' and inside place the EJS file you want to render (e.g. index.ejs), stablishing the link like this: <link rel="stylesheet" href="/css/styles.css">:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/css/styles.css">
<title>Document</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
In this case, you should be able to see the css code applied in the home route "/", rendering the index.ejs file. I hope it help you!

Express.js not sending css file

I am setting up a web server with exprss.js and socket.io. I set up a static folder so I can link my stylesheets without having to send every single file. But I am getting this error
Refused to apply style from 'http://localhost:3000/public/styles/index.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
this is my app.js file
const express = require("express");
const app = express();
var server = require('http').Server(app);
var io=require('socket.io')(server);
app.use(express.static('public'));
app.get('/', function (req, res) {
res.sendFile(__dirname + '/public/views/index.html');
});
io.on('connection', function(socket){
socket.emit('chat message', {hello: 'world'});
socket.on('chat message', function (data){
console.log(data);
});
});
server.listen(3000);
the index.html page looks like this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link type="text/css" rel="stylesheet" href="/public/styles/index.css">
</head>
<body>
<p>yo</p>
</body>
</html>
the file structure is the following
|-public
|-styles
-index.css
|-views
-index.html
-app.js
I think there is something wrong with my server setup
This is my first time using node
You get this error usually when there is no CSS file under that link.
When you use app.use(express.static('public')); directly express serves everything under root endpoint.
So you can use <link type="text/css" rel="stylesheet" href="/styles/index.css">.
If you would like to use /public/xxx.css you can use
app.use('public', express.static('public'));
When you use static, the original folder is not included in the path url, try something like this :
<link type="text/css" rel="stylesheet" href="/styles/index.css">

Express Only loads main page

I'm trying to learn express. I'm using FS to load my HTML Page. The only thing I could find on this with a google search was using ASP.NET instead of Express.
Server.js:
var express = require('express');
var path = require('path');
var fs = require('fs');
var app = express();
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname+'/')))
app.get('/', function(a,b,c){
fs.readFileSync('index.html');
});
app.post('/testaction', function(a,b){
console.log(a.body.log);
fs.readFileSync('Logged.html');
});
app.listen(3000);
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<form method="post" action="http://localhost:3000/testaction">
<h1>Log This:</h1>
<input type="text" name="log"/>
<input type="submit", value="Press Me!"/>
</form>
</body>
</html>
In order to serve files you don't have to use fs. Example:
app.get('/', function(req, res, next) {
res.render('index');
});
If you need to redirect, you can use:
res.redirect('/staticFile.html');
Remove these lines:
app.get('/', function(a,b,c){
fs.readFileSync('index.html');
});
This line is middleware and it applies to all routes on every request:
app.use(express.static(path.join(__dirname+'/')))
It's purpose is to serve static files from whatever path you provide. In this case you're serving from the root directory so you can navigate to all your code files like http://localhost:3000/package.json for example.
It applies to all HTTP methods, get post put etc...
When you write app.get('/' you override that middleware with a new route and try serving only one file. Just drop that code and you'll server everything statically from the directory you specified above.
If you don't want to serve your code files, put your static files in a different folder such as "site" and set your static path to that folder, for example:
app.use('/', express.static(__dirname + '/site'));

AngularJS Node app downloads instead of loading in Internet Explorer

Whenever I try loading my AngularJS webpage (on a node js + express server) through http://localhost:3000, Internet Explorer just tries to download it with a random name and no file extension, instead of showing the actual page.
I can't even check the console for errors, because the download attempt seems to start before even trying to load it as a webpage.
The website works perfectly on both Firefox and Chrome. I am using Internet Explorer 11, so it's not even an old version.
I tried running my index through the W3 Validator, and the only errors it points out in the DOM are the Angular directives and tags (which are not really errors).
I tried changing the DOCTYPE from just a simple <!DOCTYPE html> to this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-loose.dtd">
And this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
... and this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
To no effect.
As suggested in other questions, I also tried serving my page as "text/plain" rather than "text/html" in my node server, but that didn't help either.
Here's the html for my index:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="it">
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<!-- Angular Material CSS now available via Google CDN; version 1.0.7 used here -->
<link rel="stylesheet" href="./modules/angular-material/angular-material.min.css"/>
<link rel="stylesheet" href="./css/style.css"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
<link rel="icon" href="icons/favicon.ico" type="image/x-icon"/>
<base href="/"/>
<title>Area Clienti</title>
<script src="./modules/angular/angular.js" type="text/javascript"></script>
<script src="./modules/ngstorage/ngStorage.js" type="text/javascript"></script>
<script src="./modules/angular-aria/angular-aria.min.js" type="text/javascript"></script>
<script src="./modules/angular-animate/angular-animate.min.js" type="text/javascript"></script>
<script src="./modules/angular-material/angular-material.min.js" type="text/javascript"></script>
<script src="./modules/angular-ui-router/release/angular-ui-router.min.js" type="text/javascript"></script>
<script src="./modules/ui-router-extras/release/modular/ct-ui-router-extras.core.min.js" type="text/javascript"></script>
<script src="./modules/ui-router-extras/release/modular/ct-ui-router-extras.dsr.min.js" type="text/javascript"></script>
<script src="./modules/ui-router-extras/release/modular/ct-ui-router-extras.sticky.min.js" type="text/javascript"></script>
<script src="./modules/pdfmake/build/pdfmake.min.js" type="text/javascript"></script>
<script src="./modules/pdfmake/build/vfs_fonts.js" type="text/javascript"></script>
<script src="./modules/angular-messages/angular-messages.min.js" type="text/javascript"></script>
<script src="http://ngmaterial.assets.s3.amazonaws.com/svg-assets-cache.js" type="text/javascript"></script>
<script src="./js/client.js" type="text/javascript"></script>
</head>
<body ng-app="App" ng-controller="AppCtrl" ng-view ui-view ng-cloak layout="row">
</body>
</html>
The script tags were in the body before, I tried putting them in the head to see if that would have helped, but it didn't.
What might be the issue here? And why is it so painful to make stuff work on IE?
EDIT: here's the server code.
var express = require("express");
var fs = require('fs');
var xml2js = require("./node_modules/xml2js");
var auth = require("./authenticator.js");
var bodyParser = require('body-parser');
var app=express();
//app.use(express.static('pages'));
var server = app.listen(3000, function(){
var host = server.address().address;
var port = server.address().port;
});
var jsonParser = bodyParser.json(); // to support JSON-encoded bodies
var urlencodedParser = bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
});
app.get('/', function(req, res){
sendFile(res, './index.html', getHeader('text/plain'));
});
app.use('/font/', express.static('./font/'));
app.use('/modules/', express.static('./node_modules/'));
app.use('/css/', express.static('./css/'));
app.use('/views/', express.static('./views/'));
app.use('/img/', express.static('./img/'));
app.use('/js/', express.static('./js/'));
function sendFile(res, path, header){
fs.readFile(path, function(err, content){
if(err) {
console.log("\nErrore caricando " + path + " - err: " + err);
//pageNotFound(res, "error");
}
else sendToClient(content, res, 200, header);
});
}
function getHeader(type){
return {"Content-Type": type};
}
function sendToClient(data, res, code, type){
res.writeHead(code, getHeader(type));
(type === "text/html" || type === "text") ? res.end(data, "utf-8") : res.end(data);
}
Plus a bunch of other POST and GET services which I think are not relevant
UPDATE: I managed to get it to say something in the developer console. This is the error:
(translation: impossible to open http://localhost:3000/)
It still tries to download the page.
UPDATE 2:
I managed to find out what the issue was: for some reason, the Content-Type header content was being interpreted as an object rather than the string it actually was, so IE couldn't render the page.
It now renders the index, but Angular-UI-Router doesn't seem to work.
It appears as though ui-router can't load sub states (it can switch between normal states though, since I was able to log in and be transferred to my dashboard page, which is a different state)
(Everything is still working perfectly fine on Chrome and Firefox)
Could it be sending you a file because you're using .sendFile():
app.get('/', function(req, res){
sendFile(res, './index.html', getHeader('text/plain'));
});
instead of using .render() to render the page?
app.get('/', function (req, res) {
res.render('index.html');
})
Try using Express's use() to always send via sendFile() the index.html after any HTTP action using the * wildcard. Make sure this goes after any other API REST routes or similar. This helps ensure that the Angular app within index.html is not constantly reloaded by other pages being rendered. This way any other API routes send/receive the data you need and only if nothing else is matched, will the index.html be loaded. Below is a structure that worked for me for an Express + Angular 2 application.
File Structure:
api
foo
foo.js
bar
bar.js
public
fonts
css
img
index.html
server.js
Server JS:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
// fonts, css, images are stored in respective folders within folder "public"
app.use(express.static(path.join(__dirname, 'public')));
// some RESTful endpoints
app.use('/api/foo', fooRoutes);
app.use('/api/bar', barRoutes);
app.use('*', (req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));
// error handling middleware
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});