How to pass a variable from a Node.js file to a frontend JavaScript file - javascript

I would like to know how to pass the "myBlogs" variable that I have in my Node.js file ("server.js") to a frontend JavaScript file ("blogs.js"). Once I have access to it in the JS file, I would then map through the array that is stored in that variable and output a template for each blog in an HTML file ("blogs.html").
Later, the idea is to get the blogs data from a database (MongoDB) instead of having them hard coded. I have seen how to do this with Express and a templating engine (EJS), but as practice for a beginner, I would like to understand the basics of if and how it can be done without these tools.
My file structure:
blogs.css
blogs.html
blogs.js
server.js
server.js:
const http = require("http");
const fs = require("fs");
const myBlogs = [
{
title: "My first blog",
author: "John",
},
{
title: "My second blog",
author: "Mike",
},
];
const server = http.createServer((req, res) => {
console.log("request made");
// set header content type
let path = "";
switch (req.url) {
case "/blogs.css":
path += "blogs.css";
res.setHeader("Content-Type", "text/css");
break;
case "/blogs.js":
path += "blogs.js";
res.setHeader("Content-Type", "text/javascript");
break;
default:
path += "blogs.html";
res.setHeader("Content-Type", "text/html");
}
// send file
fs.readFile(path, (err, data) => {
if (err) {
console.log(err);
res.end();
} else {
res.write(data);
res.end();
}
});
});
server.listen(3000, "localhost", () => {
console.log("listening for requests on port 3000");
});
blogs.js:
const container = document.querySelector("div")
const html = myBlogs.map(blog => (
`<h2>${blog.title}</h2>
<p>${blog.author}</p>`
))
container.innerHTML = html;
blogs.html:
<!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>Document</title>
<link rel="stylesheet" href="blogs.css" />
</head>
<body>
<div></div>
<script src="blogs.js"></script>
</body>
</html>
blogs.css:
p {
color: red;
}
P.S.: If such an approach is completely wrong, could you please explain the correct way this would be done without the use of Express and a templating engine?

server.js
// send file
fs.readFile(path, "utf8", (err, data) => {
if (err) {
console.log(err);
res.end();
} else {
res.write(data.replace(/%MY_BLOGS%/g, JSON.stringify(myBlogs)));
res.end();
}
});
blogs.html
<!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>Document</title>
<link rel="stylesheet" href="blogs.css" />
<script>
var myBlogs = %MY_BLOGS%;
console.log(myBlogs);
</script>
</head>
<body>
<div></div>
<script src="blogs.js"></script>
</body>
</html>
This is incredibly hacky and not a good practice at all. It basically just finds %MY_BLOGS% and interpolates a JSON encoded object. Since JSON is valid JS, it will be directly accessible in your client side JS. You can now access myBlogs in blogs.js since it's a global variable.

Instead of using HTTP you could use something like express.js with ejs to pass backend data to front end.
npm i express ejs
Now you have express.js and ejs installed write some simple code like this:
server.js
const express = require('express')
// Create new server
const app = express()
// This will read read all the files in static and add them eg;
// static/style.css would now be able to do localhost:3000/style.css
app.use(express.static("static"))
// Set the view engine from text to ejs
app.set('view engine', 'ejs')
// app.get means you are using the get method on the url "/"
app.get('/', (req,res) => {
// res.render is the method for ejs
// res.render(file, options)
res.render('blogs', {
// Now on the front end you would be able to get data
data: example
})
})
// Start listening on X port
app.listen(3000, () => {
console.log("Listening on port 3000")
})
views/blogs.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" />
<title>Document</title>
<link rel="stylesheet" href="blogs.css" />
</head>
<body>
<div>My blogs <%= locals.data %></div>
</body>
</html>
In ejs you use <% %> to run something and <%= %> to output something
Your project structure would look something like this:
static
blogs.css
blogs.js
views
blogs.ejs
server.js
You should read up on express.js and ejs

Related

socket.emit Not sending to client, but logs fine

So I have a very basic socket application. My Frontend is html, and i want to make it so were whenever i click a button, it alerts on another address. So it goes from admin.html -> index.js -> index.html and the admin.html -> index.js goes very smoothly, but index.html never recieves it.
heres index.js:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.use(express.static(__dirname+"/public"))
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('a user disconnected')
});
socket.on('epic', () => {
console.log('test');
});
socket.on('alert', (text) => {
console.log(text);
socket.emit('bans', text)
})
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
admin.html:
<!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>Admin Page</title>
</head>
<body>
<input type='text'>
<button onClick='test()'>Alert whatever</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.js" integrity="sha512-YeeA/Qxn5hYdkukScTCNNOhTrv1C2RubAGButJ1rmgQwZf/HdRaCGl+JAVkqsqaNRaYNHdheiuKKuPf9mDcqKg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const socket = io();
function test() {
let text = document.querySelector('input').value;
socket.emit('alert', text);
}
</script>
</body>
</html>
index.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>Socket.io</title>
</head>
<body>
<button onClick='test()'>Test</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.5.4/socket.io.js" integrity="sha512-YeeA/Qxn5hYdkukScTCNNOhTrv1C2RubAGButJ1rmgQwZf/HdRaCGl+JAVkqsqaNRaYNHdheiuKKuPf9mDcqKg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const socket = io();
function test() {
socket.emit('epic');
}
socket.on('bans', (text) => {
document.title = text;
})
</script>
</body>
</html>
How can I make it to where index.html receives and changes the document title? (I have tried console.log to make sure it was just my fault and the file was receiving it, but it never logged anything in the console)

Putting Data into MongoDB Collection Using URL Params

I'm currently working on a research project for my CSCI class that requires studying cyber security in great detail. Replicating what a phishing site might look like is one of the goals I've set for myself. But I'm having trouble understanding how to add information to the URL and add it to the MongoDB collection. The URL that will put the email address and password into the collection is "https://URL.com/insert?email=EMAIL#gmail.com&password=123456." I am a complete novice when it comes to creating APIs, thus I need some assistance.
I have so far made a simple form and a js file to insert the form's data into MongoDB, but I'm unable to tweak it such that it accepts parameters for URLs instead.
HTML:
<!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>Document</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1>To MongoDB</h1>
<form class="container" method="post" action="/">
<div class="form-group">
<input class="form-control" name="email">
</div>
<div>
<textarea class="form-control" name="password"></textarea>
</div>
<button>ADD</button>
</form>
</body>
</html>
JS:
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: true}));
mongoose.connect("mongodb+srv://<USERNAME>:<PASS>#<CLUSTER>.mongodb.net/Data", { useNewUrlParser: true}, { useUnifiedTopology: true})
const dataSchema = {
email: String,
password: String
}
const Data = mongoose.model("Data", dataSchema);
app.get("/", function(req, res) {
//res.send("express is working");
res.sendFile(__dirname + "/index.html");
})
//app.post
app.post("/", function(req, res){
let newData = new Data({
email: req.body.email,
password: req.body.password
});
newData.save();
res.redirect("/");
})
app.listen(3000, function() {
console.log("server is running on port : 3000");
})
You can access the url query parameters using req.query.
If your URL is https://URL.com/insert?email=EMAIL#gmail.com&password=123456
you can access the parameters with req.query.email and req.query.password
To handle blank inputs, you have to add a check
A relevant code snippet would be:
app.get("/insert", function(req, res){
if (!req.query.email || !req.query.password) {
return res.status(400).send("failed");
}
let newData = new Data({
email: req.query.email,
password: req.query.password
});
newData.save();
res.send("success");
});

I'm trying create a simple module but doesn't work. Node JS

I'm new to Node JS, on this site and English :)) Sorry for all foreign language problems.
Probably I'm getting a "return" error on this codes. When i add the hi.myFunc(); function i'm getting below following error in terminal:
_http_outgoing.js:679
if (msg.finished) {
^
TypeError: Cannot read property 'finished' of undefined
at write_ (_http_outgoing.js:679:11)
at write (_http_outgoing.js:661:15)
at Object.module.exports.myFunc (C:\Users\benom\Desktop\Her Şey\HTML\hi.js:3:9)
at Server.<anonymous> (C:\Users\benom\Desktop\Her Şey\HTML\app.js:12:16)
at Server.emit (events.js:315:20)
at parserOnIncoming (_http_server.js:874:12)
at HTTPParser.parserOnHeadersComplete (_http_common.js:126:17)
How can i solve this issue?
I got 3 file for this exercise.
app.js
const http = require("http");
const fs = require("fs");
const hi = require("./hi.js");
fs.readFile("./index.html", (err, data) => {
if (err) {
throw err;
} else {
http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/html; charset=utf8" });
res.write(data);
hi.myFunc(req.url, res.write);
res.end();
}).listen(3000);
};
});
hi.js
module.exports.myFunc = function (url, res) {
if (url === "/") {
res("huh");
};
};
index.html
<!DOCTYPE html>
<html lang="tr">
<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>Document</title>
<style>
body {
background-color: rgba(15, 15, 15, .96);
color: rgb(255, 255, 255);
}
</style>
</head>
<body>
</body>
</html>
If you want to pass res.write to some other function, you can .bind() the object to it as in:
hi.myFunc(req.url, res.write.bind(res));
Without this, the res object gets lost when you pass it to another function and you end up only with a reference to then .write. Then, when someone tries to call it, it's not called with the proper object and it causes an error.

Express how to re-direct json data through different endpoints

I'm pretty new to using express and the responses here on StackOverflow have been very confusing. What I have is JSON data that I am retrieving using app.get(). What I want is to modify this data and send it to my index.html file. I know that I can simply use the fetch function to get the data in my index file from the get endpoint but I need to use both the app.post() and app.put() function.
I'm having trouble understanding your question.
Here's a sample code that uses axios and plain vanilla javascript to get some data from backend and then in frontend, you can modify the data. You can replace axios for fetch and it'll still work.
app.js
const express = require("express");
const bodyParser = require("body-parser");
const port = 8000;
const app = express();
/* Simulating data, a better approach would be to use some storage like MySQL... */
let data = {
name: "Elon Musk",
age: "48",
height: "1.88m"
};
app.use(express.static("public"));
/* body-parser is required so the server can parse the data sent. */
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
/* get the data... */
app.get("/api/mydata", function(req, res) {
return res.json(data);
});
/* this is where the client will post the data */
app.post("/api/newdata", function(req, res) {
data.name = req.body.name;
data.age = req.body.age;
return res.json("OK!");
});
app.listen(port, function() {
console.log("Listening on 8000");
});
public/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>
<input type="text" id="name" placeholder="Name..." value="">
<input type="text" id="age" placeholder="Age..." value="">
<button type="button" id="setValues">Change values!</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.js"></script>
<script>
window.addEventListener("load", function() {
axios.get("/api/mydata").then(function(res) {
document.getElementById("name").value = res.data.name;
document.getElementById("age").value = res.data.age;
})
});
document.getElementById("setValues").addEventListener("click", function() {
axios.post("/api/newdata", {
name: document.getElementById("name").value,
age: document.getElementById("age").value
}).then(function(res) {
console.log("Sent!");
})
})
</script>
</body>
</html>
If you have any questions, let me know!

Get file path from request

I have the following files:
app.js
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
app.listen(8000);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
index.html (only the 'head' is shown here):
<html lang="en" ng-app="Client">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="viewport"
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, target-densitydpi=device-dpi"/>
<link rel="stylesheet" type="text/css" href="css/app.css"/>
<link rel="stylesheet" type="text/css" href="css/bootstrap.css"/>
<link rel="stylesheet" type="text/css" href="css/slider.css"/>
<title>Web Client: Robot control</title>
</head>
I first execute my nodejs server: node app.js
When I run
http://localhost:8000/index.html
even when the request is for a different file, example: css/app.css, the server (app.js)
returns the index.html file. So my output is very wrong.
May I know how I can parse the request in app.js, to get the url field, and then extract the required file name from it?
Thank you.
SOLVED
By doing the following -
var pathname = url.parse(req.url).pathname;
console.log("Request for " + pathname + " received.");
fs.readFile(__dirname + pathname,
You will need the following line as well:
var url = require('url');
req.url
this variable is what you need, if you request 127.0.0.1:8000/index.html, the req.url is /index.html; if you request 127.0.0.1:8000/css/filename, the req.url is /css/filename

Categories