I'm using Express with Handlebars for front-end. When the selected option in the dropdown in home.handlebars changes, I want to trigger an event and read the value of the selected option in index.js. As I understand, I should use a Handlebars helper for this. I created a helper server.js (the Node.js backend) and added it to the onchange event for the dropdown. However, the handler does not seem to work. Here is my code:
server.js:
const express = require('express');
const app = express();
const handlebars = require('express-handlebars');
const port = 3000;
app.use(express.static('public'));
var handlebarsHelpers = handlebars.create({
helpers: {
dropdownChange: function (value) {
console.log("helper running.");
console.log("value is " + value);
return value;
}
}
});
app.engine('handlebars', handlebarsHelpers.engine);
app.set('view engine', 'handlebars');
app.set('views', './views');
app.get('/', (req, res) => {
res.render('home', {layout: false});
});
<...>
app.listen(port, () => {
console.log(`Server listening on port ${port}`)
});
index.js:
import * as d3 from "https://cdn.skypack.dev/d3#7";
import axios from 'https://cdn.skypack.dev/axios';
const dataSet = async function getData() {
return await axios.get('/data');
}
var courseData = [];
function getNodes() {
//************************getNodes is the function that should eventually read the dropdown value************************
}
async function drawGraph() {
const data = await dataSet();
console.log(data);
courseData = data.data;
console.log(courseData);
}
drawGraph();
home.handlebars:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Graph Chart</title>
</head>
<body>
<h2 align="center">Graph Chart</h2>
<div>
<select name="select" id="select" onchange={{dropdownChange value}}>
<option value="">Select a course...</option>
<option value="course1">course1</option>
<option value="course2">course2</option>
</select>
</div>
<svg class="prereq-graph"></svg>
</body>
</html>
<script type="module" src="./static/js/index.js"></script>
How do I fix the issue of the Handlebars helper not working? Alternatively, are there other ways to pass the dropdown selected value from Handlebars to Express when the onchange event is triggered?
Thank you.
Nevermind, I remembered that Javascript's addListener is a thing and solved my issue 🙃
Related
I am building a small project where you can generate a random hex color and then save it to database. But I don't know what I am doing wrong because my data won't save to database.
So index.js is my main file where I am declaring routes. I am using ejs for templeting and a separate file in a public folder where I write my javascript code. Can you give me a hint? Should I somehow work on my JS file where I click the button to submit the hex code somewhere?
index.js
const express = require('express');
const app = express();
const path = require('path');
const mongoose = require('mongoose');
const Color = require('./models/hexColor');
mongoose.connect('mongodb://localhost:27017/randColor', {useNewUrlParser: true, useUnifiedTopology: true})
.then(() => {
console.log("MONGO CONNECTION OPEN")
})
.catch(err => {
console.log("ERROR MONGO CONNECTION")
console.log(err)
})
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use('/public', express.static('public'));
app.use(express.urlencoded({extended: true}));
app.get('/home', (req, res) => {
res.render('homepage.ejs')
})
app.get('/hexColor', async (req, res) => {
const color = await Color.find({});
res.render('hexColor.ejs', { color });
})
app.post('/hexColor', async (req, res) => {
const newColor = new Color(req.body)
await newColor.save();
})
app.listen(3000, () => {
console.log("Listening!")
})
hexColor.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../public/hexColor.css">
<title>Hex Color Generator</title>
</head>
<body>
<form action="/hexColor" method="POST">
<div class="nav-container">
<div>
<h4 class="back-to-home">Home</h4>
</div>
<div>
<h1>Hex Color Generator</h1>
</div>
<div>
<h4>History</h4>
</div>
</div>
<div class="btn-container">
<button class="btn-generator">Click to generate</button>
</div>
<div class="color-container">
<div class="square-container">
</div>
</div>
<ul class="hex"></ul>
</form>
<script src="../public/hexColor.js"></script>
</body>
</html
hexColor.ejs
const homeBtn = document.querySelector(".back-to-home");
const btnGenerator = document.querySelector(".btn-generator");
const squareCont = document.querySelector(".square-container");
const ul = document.querySelector('.hex');
function hexChangeColor () {
var randomColor = Math.floor(Math.random()*16777215).toString(16);
var hexColor = `#${randomColor}`;
return hexColor;
}
homeBtn.addEventListener('click', function () {
window.location.href = 'http://localhost:3000/home'
})
btnGenerator.addEventListener('click', function (e) {
e.preventDefault();
squareCont.style.backgroundColor = hexChangeColor();
const li = document.createElement('LI');
li.innerHTML = hexChangeColor();
ul.appendChild(li);
})
hexSchema.js
const mongoose = require('mongoose');
const colorSchema = new mongoose.Schema({
hex: {
type: String
}
})
const Color = mongoose.model('Color', colorSchema);
module.exports = Color;
what you are getting in req.body?
Try by adding body-parser
https://www.npmjs.com/package/body-parser
Losing my mind here. I feel like I have the paths correct but for some reason my script file isn't loading/working. When I move the code to the app.js it prints out what I want to the console and works just fine but when I have it in the scripts file, it does nothing. I cant seem to find the problem.
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(express.static(`${__dirname}/public`));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
const rootRoute = require('./routes/index')
app.use('/', rootRoute);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log('server is running')
});
HTML page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>In Your Words</title>
<link rel="stylesheet" href="/stylesheets/app.css">
</head>
<body>
<script type="text/javascript" src="/scripts/logic.js"></script>
</body>
</html>
script page
const generateInputs = () => {
let randomNumber = Math.floor(Math.random() * 20);
console.log(randomNumber)
}
generateInputs();
I writirng server in Express to posibility GET and POST. In Insomnia I get and post valid data.
This is code my REST.
const express = require('express');
const app = express();
const port = 3000;
var cors = require('cors');
app.use(express.json())
app.use(express.urlencoded({extended: true}))
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({extended: true}));
let myValue = 1;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
//GET
app.get('/get', (req, res) => {
return res.json({"wartosc": myValue})
});
//POST
app.post('/post', function (req, res) {
myValue = req.body.value;
console.log(req.body)
return res.json({"wartosc": myValue});
});
Then I creaeted page with two input will be used to call the GET and POST methods of our REST server.
async function getMethod() {
let inputValue = document.getElementById("inputValue").value;
const responseGet = await fetch('http://localhost:3000/get');
const myJsonGet = await responseGet.json();
//console.log(JSON.stringify(myJsonGet));
document.getElementById("inputValue").value = myJsonGet.wartosc;
}
async function postMethod(){
let inputValue = document.getElementById("inputValue").value;
let responsePost = await fetch('http://localhost:3000/post', {
method: 'POST',
body: {'value' : JSON.stringify(inputValue)}
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<input type="text" id="inputValue">
<button onclick="getMethod()"> GET</button>
<button onclick="postMethod()">POST</button>
<script src="script.js"></script>
</body>
</html>
When I do get , I get the correct value, but when I change the value and send a post, the server prints undefined.
I don't know why, will you try to help me?
In your script.js postMethod() you should stringify the entire body:
body: JSON.stringify({'value' : inputValue})
Ideally you use querystring.stringify instead but this should also work fine.
Alternatively, you can just leave out the entire script.js with the async stuff.
Instead try with using a form and name="value". You can change the form action and method per button.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form method="GET" action="http://localhost:3000/get">
<input type="text" id="value" name="value">
<button type="submit">GET</button>
<button type="submit" formmethod="post" formaction="http://localhost:3000/post">POST</button>
</form>
</body>
</html>
I did some changes to make it work on CodeSandbox (example). Everything works.
const express = require("express");
const app = express();
const port = 3000;
var cors = require("cors");
const rand = () =>
Math.random()
.toString(36)
.substr(2);
app.use(express.static("public"));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
//GET
app.get("/get", (req, res) => {
return res.json({ getval: rand() });
});
//POST
app.post("/post", function(req, res) {
return res.json({ postval: `${rand()}:${req.body.value}` });
});
I put HTML and JavaScript files in the public directory.
async function getMethod() {
const responseGet = await fetch("/get");
const myJsonGet = await responseGet.json();
document.getElementById("inputValue").value = myJsonGet.getval;
}
async function postMethod() {
let inputValue = document.getElementById("inputValue").value;
let options = {
method: "POST",
body: JSON.stringify({ value: inputValue }),
headers: {
"Content-Type": "application/json"
}
};
let responsePost = await fetch("/post", options);
let myJsonPost = await responsePost.json();
document.getElementById("inputValue").value = myJsonPost.postval;
}
Both when you send JSON data via GET and POST, you must extract it with response.json(). In addition, when submitting POST data, you must set a header that is JSON. Without it, the server will not recognize that the transmitted data is in this format.
I need to pass a variable from a NodeJS file to a rendered html file. How to do that?
Here below what I had tried
Nodejs code
const loginRouter= express.Router();
const config= require('../config/config.json');
loginRouter.get('/', (req,res)=>{
res.render(path.dirname(__dirname)+'/views/login.html',{version:config.version});
//res.json('done')
});
HTML Code
<label style="font-size:10px;float: right;"><%= version %></label>
Current Result:-
Nothing is coming
Expected Result:-
<label style="font-size:10px;float: right;">3.9</label>
I have set this version number in my config which I have imported in my login.js, but still, I am not getting the output. Does anyone have any idea about it?
If you don't want to use a templating engine like ejs or pug then you can just send a get request with axios or fetch to your node server and send a response.
Here's a sample on how you can do it. Change it according to your needs.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1 id="title">My page</h1>
<script>
fetch('http://localhost:5000/version').then(function(response) {
return response.json();
}).then(function(myJson) {
document.getElementById('title').innerHTML = myJson;
});
</script>
</body>
</html>
server.js
const express = require('express');
const app = express();
const PORT = 5000;
app.get('/', (req, res) => {
res.sendFile('index.html', {root: __dirname });
});
app.get('/version', (req, res) => {
const myVersion = 'My version is 0.5';
res.json(myVersion);
});
app.listen(PORT, () => {
console.log(`Server running on PORT ${PORT}`);
});
Can anyone tell me why this code will work perfectly in an HTML page when accessing the data from my hard drive but when I add it to express and node I get a
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
with perfectly formatted code. I know I tested it with a formatter and I even manually created a json object. Here is the code:
<html>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Untitled</title>
</head>
<body>
<div id="output"></div>
<button id="getProperty">Get Property</button>
<script>
document.getElementById('getProperty').addEventListener('click', getProperty);
function getProperty() {
fetch('2016-regular.json')
.then((res) => res.json())
.then((data) => {
let output = '<h2>Property</h2>';
console.log(data);
data.propertystandings.propertystandingsentry.forEach(function(propertyEntry){
output += `
<ul>
<li>id: ${propertyEntry.property.ID}</li>
<li>city: ${propertyEntry.property.City}</li>
<li>prop name: ${propertyEntry.property.Name}</li>
<li>prop name: ${propertyEntry.rank}</li>
</ul>
`;
});
document.getElementById('output').innerHTML = output;
})
}
</script>
</body>
</html>
</html>
</html>
But then this code in express causes the error- same exact file that worked perfectly before ran thru express now causes this error:
**"index.ejs"**
<div id="output"></div>
<button id="getProperty">Get Property</button>
<script>
document.getElementById('getProperty').addEventListener('click', getProperty);
function getProperty() {
/*fetch('sample.txt')
.then(function(res) {
return res.text();
})
.then(function(data){
console.log(data);
});*/
fetch("2016-regular.json")
.then((res) => res.json())
.then((data) => {
console.log(data);//**won't even read the data without that error**
});
}
</script>
**express code**
var express = require('express');
//var bodyParser = require('body-parser');
var cors = require('cors');
var path = require('path');
var app = express();
app.use(bodyParser());
app.use(cors());
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.get('/', function (request, response) {
response.render('index.ejs');
});
app.listen(8000, function() {
console.log('running on 8000');
});
any ideas why this works fine in plain html when accessing a folder or if I manually create and save the file on my hard drive but once I put it in express or try to access the API the data came from (the final goal) I get the error SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
I think the bottom line is that you need to make sure your JSON file is reachable/loadable, and then make sure it is valid. Here is a minimal working example. You app.js should be simply:
var express = require('express');
var index = require('./routes/index');
var app = express();
app.set('views', 'views');
app.set('view engine', 'ejs');
app.use(express.static('public'));
app.use('/', index);
module.exports = app;
Your routes/index.js is simply:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
And your views/index.ejs should be:
<html>
<body>
<div id="output">JSON contents will appear here.</div>
<button id="getProperty">Click to load JSON</button>
<script>
document.getElementById('getProperty').addEventListener('click', getProperty);
function getProperty() {
fetch("./2016-regular.json")
.then((res) => res.json())
.then((data) => {
document.getElementById('output').innerHTML = JSON.stringify(data);
});
}
</script>
</body>
</html>
Finally, make sure your JSON file is saved at ./public/2016-regular.json. Here is mine:
{
"item1": "value1",
"item2": "value2",
"item3": "value3"
}
TEST 1 Make sure your JSON file is reachable my pointing your browser to http://localhost:3000/2016-regular.json (note you may have to change the port if you are running on a different port).
TEST 2 Navigate to http://localhost:3000/ and click on the button. The file contents should appear in the results div.
Full working code is available here. Just clone the repository, then
cd exp1
npm install
npm start