I am working on a project to manage printers with CUPS command-line, I have multiple "api's" that make different thinks, for now i just want so see my parsed JSON result in a view, but I'm clueless on how to pass that value trough Express and then render it in a EJS view:
my api:
const spawnSync = require("child_process").spawnSync;
const parseStdout = require('../utils/utils.js');
function lpstat(){
let printerList = spawnSync("lpstat -p", {
timeout: 10000,
encoding: "utf-8",
});
let parsedList = parseStdout(printerList);
let onlyPrinterList = parsedList.filter(function (line) {
return line.match(line.match(/^printer/) || line.match(/^impressora/));
});
let onlyPrinterNames = onlyPrinterList.map(function (printer) {
return printer.match(/(?: \S+)/)[0].trim();
});
process.on('exit', (code) => {
process.kill();
});
//this is what i want to pass to the view
return JSON.stringify(onlyPrinterNames);
}
my app.js
const express = require('express');
const app = express();
app.listen(3000);
app.set('view engine', 'ejs');
app.get('/lpstat',(req,res) => {
//what should i use here?
res.render('lpstat')
});
my lpstat.ejs
<html lang="en">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>lpstat</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
<p>lpstat result:</p>
<%= what should i use here?%>
</body>
</html>
The second parameter in res.render defines the data that is given to your templates:
app.get('/lpstat',async (req,res) => {
// Call your api here to fill the variable
const printers = lpstat()
res.render('lpstat', {
printers
})
});
You will be able to use this in your ejs template then
<p>lpstat result:</p>
<%= printers %>
You will need to replace callApi with whatever function is used to fetch your data. I used async/await for a simpler answer, can be done with callbacks as well.
Related
I am creating a youtube video downloader with express, html, javascript and later on I want to switch to vue.js.
This is my code:
Index.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>
</head>
<body>
<h1>My Own Youtube downloader</h1>
<input class="URL-input" type="text" placeholder="enter...">
<button class="convert-button">Convert</button>
<script src="script.js"></script>
</body>
</html>
Script.js
var convertBtn = document.querySelector(".convert-button");
var URLinput = document.querySelector(".URL-input");
convertBtn.addEventListener("click", function () {
console.log("URL : ${URLinput.value}");
sendURL(URLinput.value);
});
function sendURL(URL) {
window.location.href = `http://localhost:4000/download?URL=${URL}`;
}
Server.js
const express = require("express");
const cors = require("cors");
const ytdl = require("ytdl-core");
const app = express();
app.use(cors());
app.listen(4000, () => {
console.log("Server is working at port 4000 !!");
});
app.get("/download", (req, res) => {
var URL = req.query.URL;
res.header("Content-Disposition", 'attachment; filename="video.mp4');
ytdl(URL, {
format: "mp4",
}).pipe(res);
});
Right now, everything works fine.
I just want to implement the functionality so you can see the youtube video on the frontend in the html.
Does anyone know how to implement this functionality?
PS: I rather don't use a database, only node and express for now
on server.js use
app.get("/download/:URL", (req, res) => {
var URL = req.params.URL;
res.header("Content-Disposition", 'attachment; filename="video.mp4');
ytdl(URL, {
format: "mp4",
}).pipe(res);
});
and main file, use
document.getElementById('video').src=`localhost:8080/download/${URL}`;
And in html file add
<video id="video" width="320" height="240" controls>
</video>
I'm following a Node.js course with refresh tokens and in some part of the code I started getting this error and I couldn't figure out what might be causing it.
I followed the course and my requests always worked well, but there was a class where the tutor needed to modify some parts of the code. I grabbed the files from GitHub to see what changed and modified my code as well. But from then on my postman requests didn't work anymore.
On Postman I have this error message
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /usuario</pre>
</body>
</html>
In my VS Code terminal the API is working normally.
My server.js file is
require('dotenv').config()
const app = require('./app');
const port = 3000;
require('./')
require('./database');
require('./redis/blocklist');
const routes = require('./rotas');
routes(app);
app.listen(port, () => console.log("A API está conectada!"))
My routes.js code is
const posts = require('./src/posts');
const usuarios = require('./src/usuarios');
module.exports = app => {
posts.rotas(app);
usuarios.rotas(app);
};
My user-routes.js code is
const usuariosControlador = require('./usuarios-controlador');
const middlewaresAutenticacao = require('./middlewares-autenticacao');
module.exports = (app) => {
app.route('/usuario/login')
app.post(middlewaresAutenticacao.local, usuariosControlador.login);
app.route('/usuario/logout')
app.get(middlewaresAutenticacao.bearer, usuariosControlador.logout);
app.route('/usuario')
app.post(usuariosControlador.adiciona)
app.get(usuariosControlador.lista);
app.route('/usuario/:id')
app.delete(middlewaresAutenticacao.bearer, usuariosControlador.deleta);
};
My code is on GitHub: https://github.com/Stephani0106/Seguranca-com-NodeJS
And my tutor's code is: https://github.com/alura-cursos/blog-do-codigo-2
So whats happening is I have a reactjs project that has react router. So when I try and hit /dashboard/stream it's getting the index.html off the server but then the css and js are getting 301 errors and it's not displaying anything.
express server
const express = require('express');
const {
createServer
} = require('http');
const io = require('socket.io');
const haiku = require('./haiku');
const app = express();
const server = createServer(app);
const userIds = {};
const noop = () => {};
app.use('/*', express.static(`${process.cwd()}/../client`));
/**
* Random ID until the ID is not in use
*/
function randomID(callback) {
const id = haiku();
if (id in userIds) setTimeout(() => haiku(callback), 5);
else callback(id);
}
/**
* Send data to friend
*/
function sendTo(to, done, fail) {
const receiver = userIds[to];
if (receiver) {
const next = typeof done === 'function' ? done : noop;
next(receiver);
} else {
const next = typeof fail === 'function' ? fail : noop;
next();
}
}
/**
* Initialize when a connection is made
* #param {SocketIO.Socket} socket
*/
function initSocket(socket) {
let id;
socket
.on('init', () => {
randomID((_id) => {
id = _id;
userIds[id] = socket;
socket.emit('init', {
id
});
});
})
.on('request', (data) => {
sendTo(data.to, to => to.emit('request', {
from: id
}));
})
.on('call', (data) => {
sendTo(
data.to,
to => to.emit('call', { ...data,
from: id
}),
() => socket.emit('failed')
);
})
.on('end', (data) => {
sendTo(data.to, to => to.emit('end'));
})
.on('disconnect', () => {
delete userIds[id];
console.log(id, 'disconnected');
});
return socket;
}
module.exports.run = (config) => {
server.listen(config.PORT);
console.log(`Server is listening at :${config.PORT}`);
io.listen(server, {
log: true
})
.on('connection', initSocket);
};
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<link href="/dist/css/app.min.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="/dist/js/app.min.js"></script>
</body>
</html>
how come my index.html is loaded but then the js and css isnt.
folder structure is this:
server
...
client
dist
css
js
index.html
...
To me I can't see if it's loading that index.html file how it can't load the css and js that are linked to it.
The problem is that you are using absolute path for the static files because they start with a / so if the url is /dashboard/stream then it will tries to load the css and js file from /dashboard/dist/....
To fix it remove the / from the beginning of the path to have a relative path.
<link href="dist/css/app.min.css" rel="stylesheet">
and
<script type="text/javascript" src="dist/js/app.min.js"></script>
This does the trick with Angular so why not with React considering that you are using front-end routing:
Use an absolute path in your server.js file:
app.use('/public', express.static(path.join(__dirname, '../client/dist')));
Serve your front-end routes in your server.js file:
app.get('*', function(req, res, next) {
res.sendFile("../client/index.html", { root: __dirname });
});
Now you should be able to access all the files inside the dist directory.
f.e: <script type="text/javascript" src="./public/js/app.min.js"></script>
Is it possible to "listen" an input text field at nodejs ?
I want to use a search input on my html page and i want to listen "live" any value that user types. Not to take the final value with a submit button and body parser.
I try to add an event listener after select my html input, but my selector is undefined.
here is my server.js file
// 3rd part modules
const express = require('express')
const hbs = require('hbs')
const fs = require('fs')
const moment = require('moment')
// App modules
const userData = require('./fetch')
// App basic configs
const port = process.env.PORT || 3000
const app = express()
//Log when someone is on app
app.use((req, res, next) => {
const now = moment().format("D MMM YYYY, HH:mm")
const clientIp = req.ip
const log = `${now}: from ${clientIp}`
fs.appendFile('server.log', `${log}\n`, (err) => {
if (err) throw err
})
next()
})
// Maintenance mode
// app.use((req, res, next) => {
// res.render('maintenance.hbs', {
// pageTitle: 'Maintenace mode'
// })
// })
// Express middleware to store public files & static pages
app.use(express.static(`${__dirname}/public`))
// View engine Handlebars
app.set('view engine', 'hbs')
// Use partials for header and footer
hbs.registerPartials(`${__dirname}/views/partials`)
// Pass custom functions everywhere
hbs.registerHelper('getCurrentYear', () => {
return new Date().getFullYear()
});
app.get('/', (req, res) => {
res.render('home-page.hbs', {
welcomeMessage: 'Welcome to home page',
pageTitle: 'Home page',
location: userData.location,
currentTemp: userData.currentTemp,
feelTemp: userData.feelTemp
})
})
// Don't forget the command to nodemon to see changes on hbs files
// nodemon server.js -e js,hbs,html,css
app.listen(port, () => {
console.log(`Server is up on ${port}`)
})
Here is my fetch.js file
// 3rd part library
const axios = require('axios')
// Input selection
const locationInput = document.querySelector('#locationInput').value()
// Encode user data & Use it to fetch his location
const encodedAddress = `greece${encodeURIComponent(locationInput)}`
const geocodeUrl = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodedAddress}&key=AIzaSyAnzbpJRrrx9xl2ZjRdwOx4APrn-zgVscM`
const getWeatherData = async (encodedAddress) => {
const location = await axios(geocodeUrl)
if (location.data.status === 'ZERO_RESULTS') {
throw new Error('Unable to find that address.')
}
const lat = location.data.results[0].geometry.location.lat
const long = location.data.results[0].geometry.location.lng
const weatherUrl = `https://api.darksky.net/forecast/95886b065ed14ca53b317610064fe04a/${lat},${long}?units=ca`
const weatherData = await axios.get(weatherUrl)
return {
location,
weatherData
}
}
getWeatherData(encodedAddress).then((info) => {
const location = info.location.data.results[0].formatted_address
const currentTemp = info.weatherData.data.currently.temperature
const feelTemp = info.weatherData.data.currently.apparentTemperature
return {
location,
currentTemp,
feelTemp
}
}).catch((e) => {
if (e.code === 'ENOTFOUND') {
console.log('Unable to connect to API servers')
} else {
console.log(e.message)
}
})
module.exports = {
location,
currentTemp,
feelTemp
}
And here is my html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Home</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
{{> header}}
<p>{{welcomeMessage}}</p>
<p>This is home page</p>
<input id="locationInput" type="text" placeholder="Location">
<p>{{location}}</p>
<p>{{currentTemp}}°C</p>
<p>Feels like {{feelTemp}}°C</p>
{{> footer}}
</body>
</html>
You can use event onchange of that input to send request like ajax or socket.io,etc.
onchange may be is different (onChange in reactjs, .change() method for jquery, ...)
I've been trying to learn NodeJS following
this NodeJs Youtube Tutorial.
I already worked with the Fetch API for a couple of months to get data from WordPress and Google Sheets back ends.
The last videos of the Youtube playlists are about creating a To Do List app with NodeJS and the npm's express, EJS and body-parser.
However, at part 4 of the To do list app, this "teacher" is using jQuery with Ajax to POST data to NodeJS (His jQuery Code Snippet). Since I've only been working with fetch() for AJAX POST requests, i wanted to continue with this method in plain JavaScript.
My ejs file, called todo.ejs, storing the HTML Template of the page looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/style.css">
<!-- Works because of express middleware.
Since we stored the public folder as a static folder,
we can request anything within that folder from the url, such as
127.0.0.1:3000/assets/styles.css
-->
<title>Todo List</title>
</head>
<body>
<h1>My Todo List</h1>
<div id="todo-table">
<form>
<input type="text" name="item" placeholder="Add new item..." required>
<button type="submit">Add Item</button>
</form>
<ul>
<% todos.forEach(todoList =>{ %>
<li> <%= todoList.item %> </li>
<% }) %>
</ul>
</div>
</body>
<script src="/assets/script.js"></script>
</html>
My script.js (linked to the todo.ejs page) looks like this:
document.addEventListener("DOMContentLoaded", function (event) {
let submitButton = document.querySelector("button");
let textField = document.querySelector("input");
submitButton.addEventListener("click", addItem);
function addItem() {
let newItem = textField.value;
let todo = {
item: newItem
};
fetch("/todo", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(todo)
}).then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.log(err))
}
});
And my controller handling all get/post requests, called todoController.js, looks like this:
let bodyParser = require("body-parser");
let urlencodedParser = bodyParser.urlencoded({ extended: false });
// Have some items already in place
let data = [{item: "Get milk"} , {item: "Walk dog"} , {item: "Clean kitchen"}];
module.exports = function (app) {
//Handle get data requests
app.get("/todo", function (req, res) {
res.render("todo", {todos: data});
});
//Handle post data requests (add data)
app.post("/todo", urlencodedParser, function (req, res) {
console.log(req.body);
});
//Handle delete data requests
app.delete("/todo", function (req, res) {
});
};
Now, every time i populate the input field with some text and hit the enter button, my terminal outputs empty objects:
Based on those empty objects, there has to be something wrong that my POST requests are not accepted/sent correctly.
My file tree looks like this:
Anyone who maybe has (probably an obvious) answer to this?
(I know I could just grab his jQuery Ajax code snippet to make it work, but I'm eagerly trying to understand it using plain Javascript)
Thanks in advance to everyone taking time to help me :)
You need to use bodyParser.json instead of bodyParser.urlencoded.
As the names imply, urlencoded will parse url parameters while bodyParser.json will parse json in the body of the request.
I had the same problem but my express's version was > 4.5 so i used :
const express = require('express');
app = express()
app.use(express.json({
type: "*/*"
}))
instead of :
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json())
the problem was fixed by using the parameter {type : '/'} to accept all received content-types.