I'm a Javascript and Nodejs newb and I'm not sure how to best organize things. I'm writing a web interface for a C++ application by using Nodejs and V8 convert to wrap a C++ API. The question I have is, is there some way I can use Express to serve HTML that has references to functions/global inside nodejs? Or do I have to resort to having a bunch of res.write(html) types of calls in the HTML in order to do that?
For example, I want to prefill form data with stuff that's accessed from a C++ configuration API. The C++ API is wrapped in a Nodejs module. Right now anything that needs to be dynamically generated (like prefilled forms) I just do something like,
var novaconfig = require('./NodeAppConfig/build/Release/appconfig');
var AppConfiguration = new Appconfig.AppConfigBinding();
var express=require('express');
var app = express.createServer(express_options);
app.configure(function () {
app.use(express.methodOverride());
app.use(express.bodyParser());
app.use(app.router);
});
app.get('/configureApplication.html', function(req, res) {
console.log("[200] " + req.method + " to " + req.url);
res.writeHead(200, "OK", {'Content-Type': 'text/html'});
res.write('<HTML>');
res.write('<HEAD>');
res.write(' <link rel="stylesheet" type="text/css" href="configstyle.css" media="screen">');
res.write('</HEAD>');
res.write('<BODY>');
res.write('<label>');
res.write(Interface);
res.write('</label>');
res.write('<form method="post" action="/configureNovaSave">');
res.write('<input type="text" name="interface" value="');
res.write(AppConfiguration.GetCurrentInterface());
res.write('" /><br />');
res.write('<input type="submit" name="submitbutton" id="submitbutton" value="Save Settings" />');
res.write('</form>');
res.write("<br/>");
res.write('</BODY>');
res.write('</HTML>');
res.end();
});
But this is obviously a bad way to do it. Is there a way to have the dynamically generated HTML in a stand alone file and then still access AppConfiguration.GetCurrentInterface() within it? What's a good way to organize the files for something like this?
I think what you want is a template engine. Maybe take a look at Jade or Mustache. Then you just pass in the parts you want to be dynamic and the engine renders the page for you.
The code would look something like the following
app.get('/configureApplication.html', function(req, res) {
var config = AppConfiguration.GetCurrentInterface();
res.render('configureApplication.jade', {locals: {config: config}});
});
configureApplication.jade can access the variable 'config' as follows
doctype 5
html(lang="en")
head
title= config
Full documentation here
http://jade-lang.com/
Related
So at the moment, the approach I am taking is I'm using this code to retrieve my html file.
app.get("/", function (request, response) {
response.sendFile(__dirname + "/public_html/index.html");
})
The html file is a form with method="post" and a button to submit the form. I have imported the relevant css code here.
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
Back on the js side I have use this code to collect the values from the html form when it is submitted.
app.post("/survey", function (request, response, next) {
let firstname = request.body.fname;
let surname = request.body.sname;
etc...
Then here is the part where I'm not sure whether or not I'm taking the wrong approach or not.
I use some response.write() methods to display the form results.
response.write('<h1>SURVEY REPORT</h1>');
response.write('<dl><dd><strong>Firstname entered: </strong>' + firstname + '</dd>');
response.write('<dd><strong>Surname entered: </strong>' + surname + '</dd>');
etc...
While this does kind of work, it doesn't seem to implement the css stylesheet at all. How would I get the css stylesheet to work with the output?
I have also tried creating a sql database in memory via sqlite3 and store the values there, but now I'm stuck with how I would use that table to output into an html format.
It is not a better way to do
You can you Handlebars or ejs.
Add this line on app.js
app.set('view engine', 'hbs');
Then you can response to the request by :-
res.render('/filepath/index.hbs', {write variables for the file as json})
I'm learning Express / Node. I'm trying to build a simple HTML form which I validate client - side (e.g, with jQuery / AJAX) but I also serve from the server - side (with Express.js). To be clear, the app is now simple enough that I could do everything client - side, but I want to build server - side behavior to learn the entire pipeline.
Here's the form. Note the button of type button with name change-color; this is a button that I use for debugging purposes, explained later. I am also including jquery v.3.6.0 and my own client.js file.
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>A MWE</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>A simple form.</h1>
<form action="/" method="post">
<input type="text" name="num1" placeholder = "First Number" value=""> <br>
<input type="text" name="num2" placeholder = "Second Number" value=""> <br>
<button type="submit" name="submit">Calculate</button>
<button type="button" name="change-color">Change color</button>
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="client.js" charset="utf-8"></script>
</body>
</html>
In the form, the user is supposed to give me two numbers, which the server will then sum and return. Server code is inside a file called server.js, outlined below:
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.urlencoded({extended:true}));
app.listen(3000, () => {
console.log("Server spun on port 3000.");
});
app.get("/", (req, res) => {
console.log("Serving a GET request at root route.");
res.sendFile(absoluteDirPath() + "index.html");
});
app.post("/", (req, res) => {
console.log("Serving a POST request at root route.");
const num1 = Number(req.body.num1);
const num2 = Number(req.body.num2);
res.send("<h3>Result: " + (num1 + num2) + "</h3>");
});
function absoluteDirPath() {
const path = require('path');
return __dirname + path.sep;
}
When we first access the root endpoint (GET call), the server uses res.sendFile() to send the above HTML file to the user. When the user inputs two numbers on the form and clicks on the button of type submit inside the form, the app.post() of server.js method calculates and send()s the requested sum.
Clearly I need to do some validation before I apply the summation; what if I don't get a number? Based on the answers to this post, to avoid complex and sudden redirections, I seem to have to do this on the client side, e.g, in a separate .js file. In the same post, I have been advised to author something like the following function and assign it to an event listener:
function submitFormWithoutReloading() {
$.ajax({
type: "POST",
url: "/",
data: {
num1: $('#idOfYourFirstInput').val(),
num2: $('#idOfYourSecondInput').val()
},
success: function(res) {
alert(res); // This is what the server returns
}
});
}
However, I seem to have stumbled upon a bigger issue here. I am having some trouble running all my jQuery when I serve the user with the HTML file from the app.get() method! It seems as if every time I access http://localhost:3000/, the HTML file is sent to me, but the linked client.js file is not read (and I am guessing that the same thing holds for jQuery).
To ensure that this is what my problem is, I temporarily forgot about the validation routine, made the change-color HTML button mentioned above and added some dummy code to client.js:
$(document).ready(function() {
alert("Hi!");
});
$('button[name="change-color"]').click(function() {
$("body").toggleClass("colored-background");
});
So the change-color button is used just to toggle the body element to have yellow as its background as per this CSS rule:
.colored-background {
background-color: yellow;
}
If I open index.html from my filesystem, it all works just fine; jQuery and my client.js file are loaded, the alert() comes just fine, and the button works as intended. But when I access localhost:3000 and the GET endpoint serves the client with the HTML file, it's as if the DOM scanning does not read client.js and I can't do any client - side stuff, including my much desired validation!
Any ideas of what I'm doing wrong? I know I could do everything on the client side here, but I want to learn how to split the concerns on client side and server side. Server side might want to access a DB, the client can't do everything.
// Edit: If it helps, the Chrome console says some interesting things when I load localhost:3000:
You didn't do anything wrong. This is just a common problem that everyone using node.js (including me! Cant access other files in Node.js).
You have to tell express which files can be viewed by the client. Let's create a folder called public. Inside your folder, put you .js and .css files, as well as other pictures or other assets you want accessible by the client side.
This folder, public, on your website will be replaced with your domain. Consider these files/folders:
index.js (server)
/ views
- index.html
/ public
- style.css
- client.js
- jquery.min.js
The client can only access the files inside public, like this: http://localhost:3000/style.css, or http://localhost:3000/client.js, or http://localhost:3000/jquery.min.js. However, we will not be able to access the other files (not in the public folder), unless the server explicitly gets it:
app.get('/index.html', function(req, res) {
res.sendFile(path.join(__dirname, '/views/index.html'));
});
Solution:
// ...
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, '/public')));
// You routes here
This way, the client will be able to access all the files under the public directory. Your problem should be solved.
Keep in mind: The server can still access all the files. This only restricts the client side.
I want to send a html file and an object to the client from server using express such that when the file gets loaded it uses the object and structure dynamically using ajax.
I know that the html file can be send like this:
res.sendFile( __dirname + "/" + "main.html" )
object as:
res.json(obj);
But how to send them together?
In simple word, you can not send json and html together as we need to send content-type in header. You can either send html or json.
Another way, you can send html into josn with other object something like following
const fs = require('fs');
const html = fs.readFileSync( __dirname + '/main.html' );
res.json({html: html.toString(), data: obj});
There are a couple of ways you can do that. While not the best method, this is the one I used in my projects. I used ejs, a powerful and simple templating engine.
First, install it using npm
npm install ejs
Then, in your HTML add:
<html>
<body>
<script type="text/javascript">
var obj = JSON.parse(<%= objSentFromServer %>)
// do something with obj
</script>
</body>
</html>
Server Side:
let express = require('express')
let app = express()
let ejs = require('ejs')
let fs = require('fs')
let objectSentFromServer = ... // what you need to send
app.get('/', (req, res) => {
fs.readFile(__dirname + '/main.html', (err, html) => {
res.send(ejs.render(html, JSON.stringify(objectSentFromServer)))
})
})
app.listen(8080, (err) => { console.log(err) })
Of course, there are plenty of other ways.
You may not be able to achieve this by sending back plain HTML.
But you should be able to achieve this using a templating engine. With the help of templating engine, you should be able to render a view as well as pass JSON required to used in that template.
Reference: render view
Eg;
// pass a local variable to the view
res.render('user', { name: 'Tobi' }, function(err, html) {
// ...
});
Here is the complete list of Template Engines supported by Express JS
I have a file with 10 variables stored in it, locally on my system. I want this to be available to someone else when they connect to my system. This will be used within my LAN only and not over the internet so there is no need to worry about security. I want to create a simple client-server application that uses HTTP request/response to communicate.
I can work with HTML and Javascript but I have limited knowledge of Node JS. I have created a HTML page with 10 blank labels and a "show" button. When I click on the button, I want the file to be read and each of the 10 variables to be displayed in the labels.
Here is a sample with two variables and a button.
**index.html**
<html>
<body>
<form method="post" action="/">
<fieldset>
<legend><h2>Parameters:</h2></legend>
System ID : <textarea name="my_id" id="my_id" size="2"></textarea><br >
System IP : <textarea name="my_ip" id="my_ip" size="15"></textarea><br>
<input id="show" type="submit" name="show" value="SHOW"><br>
</fieldset>
</form>
</body>
</html>
How do I go about this? Is there any easier way besides Node JS ?
If this works I would also like to over-write the variables in the same file with the user's inputs (using a different "submit" button).
I would recommend just using the http module along with the fs module for this but since you are still learning nodejs, I would recommend expressjs and flat-file-database
So when you are creating routes for your small webapp, it would probably look like this :
// Serves html file
app.get('/', function(req, res) {
res.sendFile('/index.html');
});
// Stores data from the form
app.post('/form', function(req, res) {
var data = req.body;
db.put('data', data); // Saves data to the flat file db
res.status(201);
});
// Gets data from the db
app.get('/form', function(req, res) {
var data = db.get('data');
res.status(200).json(data);
});
You would need to 'post' the data at /form in your client side code.
To get the data, simply issue a get request at /form
Also keep in mind that for express to parse form data, you need the body-parser middleware.
Oh and note that I have no idea whether flat-file db is asyncronous or not so you will probably need to check that yourself.
This is a multi part question and I'm a complete newbie to Node so please be gentle:)
I have a very simple Node/express app set up returning an index.html without using routing...
var app = express();
var port = process.env.PORT || 1337;
app.use('/i', express.static(__dirname + '/i'));
app.use('/Stylesheets', express.static(__dirname + '/Stylesheets'));
app.use(express.static(__dirname));
app.listen(port);
console.log('listening on port ' + port);
The index.html is served as a static file.
My next job is to start returning a few pages with proper routing, I've got as far as working out I need to put my routes in a routes.js file and "require" that file in my server.js file but I can't get my head around setting the routes up and every example/demo I see online seems to do it a different way. Any definitive examples of how to do this would really be appreciated.
The next part of the problem is that I want to include dynamic pages but don't know where to go with templating engines. I would like to use something "unobtrusive" so that my original HTML files still make sense when viewed in a browser.
On the front-end I would simply inject HTML into the page by first using a selector and then using the .html() method to alter the html, I could bind JSON data with a template and then inject it into the right place by looking for a classname etc. THis would be totally unobtrusive and wouldn't require any ugly {} brackets, inline javascript or directives. Psuedo code...
var data = {"name":"John"};
var result = templateEngine.bind("/template.html", data)
$('.person').html(result);
That way, I could keep my original HTML clean and viewable, like this...
<div class="person">
My Name is FirstName
</div>
The closest thing I can find is PURE - http://beebole.com/pure - but I'm not sure how to get it working with NODE (or even if it's compatible).
To add more complexity, whatever templating engine I use needs to be able to use sub-templates(partials?) so that I can include a header/footer etc which is te same on every page. I assume this can be done recursively by referencing sub-templates from within each main template where needed?
If you're still reading this then clearly you'll have worked out that I'm floundering here with a new technology and any help would be really appreciated!
but I can't get my head around setting the routes up and every
example/demo I see online seems to do it a different way. Any
definitive examples of how to do this would really be appreciated.
Not sure what you have seen different in the examples, but the general pattern is like this:
app.**[HTTP VERB]**(**[URL]**, function(req, res){
res.end('<html>hello world</html>');
});
The following code will accept all HTTP GET requests to the root URL of your site:
app.get('/', function(req, res){
res.end('<html>hello world</html>');
});
While the following code will accept all HTTP GET request to /test in your site
app.get('/test', function(req, res){
res.end('<html>hello world from the test folder</html>');
});
It's common to have a separate route for HTTP POST requests (e.g. when the user submits data back to the server). In this case the HTTP verb is POST as in the following example.
app.post('/test', function(req, res){
res.end('<html>Thanks for submitting your info</html>');
});
In this case I am embedding the code to handle the request directly rather than referencing an external routes.js as you indicated just to make the examples cleaner in this question. In a real application you'll do it by referencing an external function so that your app.js stays lean and clean.
app.get('/test', routes.NameOfFunctionToHandleGetForSlashTest);
app.post('/test', routes.NameOfFunctionToHandlePostForSlashTest);
I know this is an old question, but I have explored this topic recently, and came up with the following solution:
my original question
I have placed the following configuration on ejs:
var ejs = require('ejs');
server.configure(function(){
server.set("view options", {layout: false});
server.engine('html', require('ejs').renderFile);
server.use(server.router);
server.set('view engine', 'html');
server.set('views', __dirname + "/www");
});
This sets your view engine as ejs, your view directory as your static public html directory and tells ejs to process .html files as opposed to .ejs.
The routes can be handles like this:
server.all("*", function(req, res, next) {
var request = req.params[0];
if((request.substr(0, 1) === "/")&&(request.substr(request.length - 4) === "html")) {
request = request.substr(1);
res.render(request);
} else {
next();
}
});
server.use(express.static(__dirname + '/www'));
This routes all html requests through the view engine, and passes all other requests on down the stack to be sent as static files.
Your html can now look something like:
<%include head.html%>
<%include header.html%>
<p class="well">Hello world!</p>
<%include footer.html%>
you can have nested includes, and pass variables down into your includes. So for instance your include head can call:
<title> <%= title %> </title>
and at the top of your index page you can include an object like:
{var title: "Home"}
Anyway, maybe this will help out someone who is looking for a ultra easy way to handle includes while sticking with normal html.