I've a problem with my node.js application.
I'm using the packages connection, connection-route, socket.io and ejs.
My application provides informations to the html page (connected via socket.io), these informations are managed by an ejs template.
When I reach a destination with a parameter, like http://localhost:5001/machine/:id2, something strange happens.
The connection route code is the following:
router.get('/machine/:mac_id', function (req, res, next) {
var mac_index = req.params.mac_id.slice(1,req.params.mac_id.length);
console.log(mac_index);
res.writeHead(200, { 'Content-Type': 'text/html' });
var str = mod_fs.readFileSync(mac_route + '/index.html', 'utf8') ;
var ret = mod_ejs.render(str, {
filename: mac_route,
title: "Machine Overview",
/* other informations */
});
res.end(ret);
}
The variable mac_route contains the path to the file index.html, which is loaded correctly.
The problem lies in the mac_index variable. On the console are printed 3 rows:
id2
unctions.js
query-1.9.1.js
The first row is obviously correct, the last 2 rows are obviously not correct, infact these are two javascript files (my file functions.js and the file for jquery jquery-1.9.1.js).
These files are included in the header of the index.html file.
HTML STRUCTURE:
header.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title> <%= title %> </title>
<link rel='stylesheet' href='/style.css' type="text/css"/>
<script src="http://localhost:5001/socket.io/socket.io.js"></script>
<script language="javascript" type="text/javascript" src="functions.js"></script>
<script language="javascript" type="text/javascript" src="jquery-1.9.1.js"></script>
</head>
<body>
<div id="header">
...
</div>
<div id="page">
index.html
<% include /header.html %>
<div id="commands">
...
</div>
<div id="main">
... code of the page, manage informations received ...
</div>
<% include /footer.html %>
footer.html
<div id="footer">
...
</div>
</div> <!-- Close the "page" div opened in the header //-->
</body>
</html>
I can't find where's the mistake.
Why the file's names are taken as parameter of the req object?
The normalized URL for those files is:
http://localhost:5001/machine/functions.js
http://localhost:5001/machine/jquery-1.9.1.js
Those match your route (/machine/:mac_id), so they will be handled by it.
Try including the connect.static middleware before your routes:
app.use(connect.static(__dirname));
(this assumes your Connect app is stored in the app variable and the JS files are in the same directory as your Node script; if not, change __dirname to point to the directory where the JS files are located).
Related
My node version is v10.2.1, express version is 4.16.0, ejs version is 2.5.7.
I want to be able to change the name of the layout at a later time.
So I routing like this:
router.get('/', function(req, res, next) {
res.render('index', { title: 'my homepage' , layout: 'basic'});
});
and index.ejs
And I wrote an include in the index like this:
<% include ./layouts/basic/header.ejs %>
Now, I want to change basic to <%= layout %> but,
<% include ./layouts/<%= layout>/header.ejs %>
causes:
Could not find matching close tag for "<%".
And,
<% include ./layouts/%><%= layout %><%/header.ejs %>
causes:
Could not find the include file "./layouts/"
How can I solve it?
I am considering that you required two header views
horizontal header
vertical header
So inside views directory I have created the respective directories.
index.ejs
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<%if(layouts=='horizontal'){%>
<%include ./horizontal/header%>
<%}%>
<%if(layouts=='vertical'){%>
<%include ./vertical/header%>
<%}%>
</body>
</html>
Here I have passed layouts variable from the routes. Hope it helps you to resolve the issue.
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);
For test purposes I run Apache local web server and I'm setting up a node.js app listening on port 8888 serving as image preprocessor, but unfortunately I'm experiencing problems as described below.
The node app.js is running in the web root directory:
'use strict';
let express= require('express')
,multer = require('multer')
,upload = multer()
,app = express()
//Import imgProcessor module which we would implement later
,imgProc = require('./imgProcessor');
app.get ('/', (req, res, next)=>{
res.sendFile(__dirname+'/appmain.html');
});
app.post('/uploadImg', upload.array('pics'),
(req, res, next)=>{
//Call the convertImgs method and pass the image files as its argument
imgProc.convertImgs(req.files).then(
(imageStringArray)=>{
//After all image processing finished, send the base64 image string to client
res.json(imageStringArray)})});
app.listen(8888, ()=>{
console.log('Hosted on Port 8888')});
The appmain.html page resides in the same web root directory:
<html>
<head>
<title>Upload Image Demo</title>
<link rel="shortcut icon" href="">
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/materialize-css/dist/js/materialize.min.js"></script>
<link rel="stylesheet" href="node_modules/materialize-css/dist/css/materialize.min.css">
</head>
<body class="container">
<div class="row">
<form id="form1" class="col m4 offset-m4" action="/uploadImg" enctype="multipart/form-data" method="post">
<div class="file-field input-field">
<div class="btn">
<span>File</span>
<input type="file" multiple="" accept="image/jpeg,png" name="pics">
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Upload one or more files">
</div>
</div>
<div class="input-field">
<button type="submit" class="waves-effect waves-light btn">Submit</button>
</div>
<div class="progress" style="display:none">
<div class="indeterminate"></div>
</div>
</form>
</div>
<div class="row img-preview"></div>
<script>
$(function(){
$('#form1').on('submit', function(event){
event.preventDefault();
var data = new FormData(this);
$.each(
$('input[name="pics"]')[0].files,
function(i, file){
data.append('file-'+i, file);
});
$('.progress').css({
display:'block'
});
$.ajax({
type:'POST',
url: $(this).attr('action'),
data:data,
cache:false,
contentType: false,
processData: false,
success:function(data){
for(var i=0;i<data.length;i++){
var template =
'<div class="col m4">
<div class="card">
<div class="card-image">
<img src="'
+ data[i]
+ '"></div></div></div>';
$('.img-preview').append(template);
}
$('.progress').css({
display:'none'
});
},
error: function(err){
$('.progress').css({
display:'none'
});
}
});
})
})
</script>
</body>
</html>
When I use the URL http://localhost:8888 in the browser the html page is loaded (i.e. I can see the buttons and input fields of the form) but the resources requested in the <script> (ex.: node_modules/jquery/dist/jquery.min.js or node_modules/materialize-css/dist/js/materialize.min.js) are not loaded. By the same way the page can't benefit from the unloaded CSS stylesheet.
As opposite, if I try to use the URL http://localhost/appmain.html the page is loaded as expected (I mean: with the correct resources and CSS).
It seems that my Apache Web Server can't serve resources when handling the port number inside the URL. How can I resolve this?
EDIT
Just to simplify: let'say the node app2.js is listening on port 8888 and it has just a method (get) that send to the client the 'Hello World!' page app2main.html. No files to serve. The app2main.html page need only to load a couple of Javascript script and a CSS stylesheet.
app2.js
'use strict';
let express= require('express')
,app = express();
app.get ('/', (req, res, next)=>{
res.sendFile(__dirname+'/app2main.html');
});
app.listen(8888, ()=>{
console.log('Hosted on Port 8888')});
app2main.html
<html>
<head>
<title>Upload Image Demo</title>
<link rel="shortcut icon" href="">
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script
src="node_modules/materialize-css/dist/js/materialize.min.js"></script>
<link rel="stylesheet"
href="node_modules/materialize-css/dist/css/materialize.min.css">
</head>
<body class="container">
<h2> Hello World! </h2>
</body>
</html>
When accessing the URL http://localhost:8888 the 'Hello World!' message appears, but I get the following error (visibile by inspecting the page):
http://localhost:8888/node_modules/jquery/dist/jquery.min.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8888/node_modules/materialize-css/dist/js/materialize.min.js Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8888/node_modules/materialize-css/dist/css/materialize.min.css Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8888/node_modules/materialize-css/dist/css/materialize.min.css Failed to load resource: the server responded with a status of 404 (Not Found)
Instead I get no error (and the expected style) when accessing the URL http://localhost/app2main.html
As discussed in comments, you should use express.static to serve static content in node.js app. In your case, your static content lies in node_modules directory itself. You can try the following code to load all resources,
e.g. http://localhost:8888/node_modules/jquery/dist/jquery.min.js
app.use('/node_modules', express.static('node_modules'));
Also, you mentioned that when you access http://localhost/app2main.html, then it worked without express.static, because apache web server to serve static files similar to express.static in node.js. That's why
http://localhost/node_modules/jquery/dist/jquery.min.js was working.
Hope it clears your doubt.
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.
I have an Ubuntu 10.04 hosting server which allows me to run node.js off of it. I'm making an test homepage and I have a few files as follows:
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>iSuperMario</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script src="/nowjs/now.js"></script>
<script src="js/chat.js"></script>
</head>
<body>
<div id="wrapper">
<div id="header">
<img src="images/green_pipe_960.png">
<img src="images/orange_pipe_960.png">
</div>
<div id="chat">
<input type="text" id="text-input">
<input type="button" value="Send" id="send-button">
</div>
<div id="content">
</div>
<div id="rooms">
</div>
</div>
</body>
</html>
reset.css and style.css (which both just contain styling for the index.html page
chat.js (which contains some scripting to implement the barebones chat function for the index.html page)
server.js which is a node.js server utilizing nowjs to serve the index.html page on port 8080 of the Ubuntu server and to implement the chat function:
var fs = require('fs');
var server = require('http').createServer(function(req, response){
fs.readFile(__dirname+'/index.html', function(err, data){
response.writeHead(200, {'Content-Type':'text/html'});
response.write(data);
response.end();
});
});
server.listen(8080);
var everyone = require("now").initialize(server);
everyone.connected(function(){
console.log("Someone has joined!");
});
everyone.disconnected(function(){
console.log("Someone has left...");
});
everyone.now.distributeMessage = function(message){everyone.now.receiveMessage(message);};
So, when I view the page from the server in a browser, none of the external resources (reset.css, style.css, chat.js, green_pipe_960.png and orange_pipe_960.png) are connected properly.
How should I enable these? I mean, if I had to, and it simplified the process a great deal, I could always include the external styles and scripts in index.html. But, the images could never be embedded (at least I think xD).
Thanks!
You need to set your file structure as follows
= main
= index.html
= css
= reset.css
= style.css
= js
= chat.js
= images
= green_pipe..
= orange_pipe..
Alternatively you can change your urls to match your real file structure.
I would like to recommend you use express or something else if you want to server something beyond a very basic prototype.
This webpage might help. Serving Static Files from Node.js.