Variable not getting passed to Pug - javascript

I am creating an express.js app as part of a team project. I'm a javascipt novice, but the task ultimately fell to me. The purpose of the relevant code is to run a script when a button is clicked, using some user-defined options, then show a new page and display links for the reports that have been generated on a results page. For whatever reason, this never works the first time after the app is started, but it will work if you go back and try again. I had thought there was a synchronization issue, and there might be, but there also seems to be an issue with the array variables not being passed to pug. I've been slamming my head against the desk to this for weeks, and asked for assistance from my professor (neither of us are CS people) with no luck. Please help.
Here's the app variables, configuration, etc. at the beginning of the file:
// index.js
/**
* Required External Modules
*/
const express = require("express");
const path = require("path");
const shell = require("shelljs");
const fs = require("fs");
/**
* App Variables
*/
const app = express();
const port = process.env.PORT || "8000";
var ipAddresses;
var ipAddressesLink;
/**
* App Configuration
*/
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
app.use(express.static(path.join(__dirname, "public")));
app.use(express.static(path.join(__dirname, "reports/html")));
//code to make html forms work
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
Here's the relevant route that keeps failing me:
//Run script when post is rec'd from root and send to results page
app.post("/", (req, res) => {
//take values and create complete command for Astrum script
var commandString = 'bash /home/astrum/Main/Astrum.sh -s ' + req.body.speed + ' -h ' + req.body.host + ' -u ' + req.body.username + ' -p ' + req.body.password;
var pathToReports = './reports/html';
runScript(commandString);
readFolder(pathToReports);
renderPage();
//Iterate thru filenames to create arrays for links and link labels
function readFolder(pathValue) {
fs.readdir(pathValue, (err, files) => {
console.log(files)
//variable & method for links to html records pages
ipAddressesLink = files;
console.log(ipAddressesLink);
//variable and method to remove file extension for link labels in pug
ipAddresses = files.map(removeExtension);
});
}
//function to remove last five characters of each element
function removeExtension(value) {
return value.substring(0, value.length - 5);
};
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink, ipAddresses, title: 'Results'});
}
//function to execute command in shell
function runScript(value) {
shell.exec(value);
}
//show array on console for debugging
console.log("type of record is: " + typeof ipAddressesLink);
console.log(ipAddressesLink);
console.log(ipAddresses);
res.end();
});
Here is the pug template for the results page which is throwing the error, obviously a work in progress:
extends layout
block layout-content
div.View
div.Message
div.Title
h1 Astrum Network Analysis
div.Body
div.multiple-group
h3 Heading
select(id='whitelist', name='whitelist' size='6' multiple)
option(value="volvo") Volvo
option(value="saab") Saab
option(value="fiat") Fiat
option(value="audi") Audi
option(value="bmw") BMW
div.form-group
label(for='whitelistButton')
input(type='submit' value='Whitelist Ports')
h3 Hosts Found:
ul
each val, index in ipAddressesLink
li: a( href = val ) #{ipAddresses[index]}
And here's the error message I get:
TypeError: /home/astrum/Main/astrumApp/views/results.pug:36
34| ul
35|
> 36| each val, index in ipAddressesLink
37|
38| li: a( href = val ) #{ipAddresses[index]}
39|
Cannot read property 'length' of undefined
at eval (eval at wrap (/home/astrum/Main/astrumApp/node_modules/pug-runtime/wrap.js:6:10), <anonymous>:93:32)
at eval (eval at wrap (/home/astrum/Main/astrumApp/node_modules/pug-runtime/wrap.js:6:10), <anonymous>:116:4)
at template (eval at wrap (/home/astrum/Main/astrumApp/node_modules/pug-runtime/wrap.js:6:10), <anonymous>:119:7)
at Object.exports.renderFile (/home/astrum/Main/astrumApp/node_modules/pug/lib/index.js:452:38)
at Object.exports.renderFile (/home/astrum/Main/astrumApp/node_modules/pug/lib/index.js:442:21)
at View.exports.__express [as engine] (/home/astrum/Main/astrumApp/node_modules/pug/lib/index.js:491:11)
at View.render (/home/astrum/Main/astrumApp/node_modules/express/lib/view.js:135:8)
at tryRender (/home/astrum/Main/astrumApp/node_modules/express/lib/application.js:640:10)
at Function.render (/home/astrum/Main/astrumApp/node_modules/express/lib/application.js:592:3)
at ServerResponse.render (/home/astrum/Main/astrumApp/node_modules/express/lib/response.js:1012:7)

You should use fs.readdirSync! I'm sure fs.readdir in readFolder function is running out of your expected process order:
function readFolder(pathValue) {
//variable & method for links to html records pages
ipAddressesLink = fs.readdirSync(pathValue);
//variable and method to remove file extension for link labels in pug
ipAddresses = ipAddressesLink.map(removeExtension);
}

Try changing:
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink, ipAddresses, title: 'Results'});
}
to:
//function to render the page
function renderPage() {
res.render("results", {ipAddressesLink: ipAddressesLink, ipAddresses: ipAddresses, title: 'Results'});
}

Related

Document is not defined on node.js - How can i import a variable from another .js file to node.js server?

Edit: Actually, my problem is "How to use "value" from selection.js in the server.js ? " I want to direct user to a searching page according to his/her choice .
i am new at web programming. I have server.js and a selection.js.
server.js is a node file, and my server is in it. selection.js is my item class changer. I am changing selected item's class with selection.js and i am trying to use this selected item from server.js. When i try below codes, i am taking this shit: Document is not defined on node.js
It is really painful. I am trying to solve it about hours. But, nothing!
Pls, help me :/
selection.js :
var iconContainer = document.getElementById('iconContainer');
var icon = iconContainer.getElementsByClassName("item");
for (var i = 0; i < icon.length; i++) {
icon[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
const btnSearch = document.querySelector("#btnSearch");
btnSearch.addEventListener("click", () => {
// get the active item's value
const value = document.querySelector(".item.active span").innerText;
console.log("value: ", value);
// do fetch
});
});
}
module.exports={searchPath: "/"+value};
server.js:
var fs = require('fs');
var express = require('express');
var app = express();
var path = require('path');
app.use('/public', express.static(path.join(__dirname, 'public')));
// '/' girdisi için index.html getirilecek.
app.get('/', function (req, res) {
fs.readFile('index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
});
});
//---------------------------------------------------
// Server kuruyoruz.
var server = app.listen(8081,"127.0.0.1", function () {
var host = server.address().address;
var port = server.address().port;
console.log('Server http://' + host + ':' + port+' adresinde çalışıyor...');
});
var search = require('./public/js/selection');
console.log(search.searchPath);
So, the code you label as selection.js needs to be in your web page, either directly embedded or linked from a <script> tag so it can run in the web page in the browser.
Then, that code can make an Ajax call using the XMLHttpRequest or fetch() interfaces in the browser to a route on your server and pass the desired value.
That route on your server (which you need to define and add code for) can then examine that value and decide what data to return the the Ajax call.
Your Javascript in the web page, then receives that returned data from the Ajax call and decides what to do with it such as insert new content in the page for the user to see, cause the browser to load a different page or refresh the current page or whatever else is appropriate.

(crypto.js) TypeError: Data must be string or buffer

I am currently using crypto.js module to hash things. It was working for a while then I started getting this error:
Here is the foundation of my server:
process.stdout.write('\033c'); // Clear the console on startup
var
express = require("express"),
app = express(),
http = require("http").Server(app),
io = require("socket.io")(http),
path = require("path"),
colorworks = require("colorworks").create(),
fs = require("fs"),
crypto = require("crypto");
function md5(msg){
return crypto.createHash("md5").update(msg).digest("base64");
}
function sha256(msg) {
return crypto.createHash("sha256").update(msg).digest("base64");
}
http.listen(443, function(){
// Create the http server so it can be accessed via 127.0.0.1:443 in a web browser.
console.log("NJ project webserver is running on port 443.");
// Notify the console that the server is up and running
});
app.use(express.static(__dirname + "/public"));
app.get("/", function(request, response){
response.sendFile(__dirname + "/public/index.html");
});
I am aware that these functions are creating the problem:
function md5(msg){
return crypto.createHash("md5").update(msg).digest("base64");
}
function sha256(msg) {
return crypto.createHash("sha256").update(msg).digest("base64");
}
The problem being, if these functions don't work (which they don't anymore), roughly 200 lines of code will go to waste.
This error is triggered by attempting to hash a variable that does not exist:
function md5(msg){
return crypto.createHash("md5").update(msg).digest("base64");
}
function sha256(msg) {
return crypto.createHash("sha256").update(msg).digest("base64");
}
md5(non_existent); // This variable does not exist.
What kind of data are you trying to hash ? Where does it come from ?
I would check the value of msg first then I would try :
crypto.createHash('md5').update(msg.toString()).digest('hex');
You could also use these packages instead:
https://www.npmjs.com/package/md5
https://www.npmjs.com/package/js-sha256

How do you use a Node.js variable on the client-side?

I'm relative new to NODEJS and I'm struggling with a basic problem, which is the correct use of global variables, I read a lot about it but it seems I can't make it work properly, I'll post some codes for a better view of the problem.
I have this simple js running as a server:
myapi.js
var http = require('http');
var express = require('express');
var app = express();
var exec = require('child_process').exec, child;
var fs = require('fs');
var jUptime;
var ipExp = require('./getDown');
var filesD = [];
var path = "/media/pi/01D16F03D7563070/movies";
app.use(express['static'](__dirname ));
exec("sudo /sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{print $1}'", function(error, stdout, stderr){
ip = stdout;
exports.ipAdd = ip;
console.log(ip);
});
app.get('/files', function(req, res) {
fs.readdir(path, function(err, files) {
if (err){
console.log("Non riesco a leggere i files");
}
filesD=files;
console.log(filesD);
});
res.status(200).send(filesD);
});
app.get('/up', function(req, res) {
child = exec("uptime -p", function(error, stdout, stderr){
jUptime = [{uptime: stdout}];
});
res.status(200).send(jUptime);
});
app.get('*', function(req, res) {
res.status(404).send('Richiesta non riconosciuta');
});
app.use(function(err, req, res, next) {
if (req.xhr) {
res.status(500).send('Qualcosa è andato storto');
} else {
next(err);
}
});
app.listen(3000);
console.log('Server attivo sulla porta 3000');
And then I have this JS used in a simple web page:
getDown.js
var ip = require('./myapi').ipAdd;
function gDownloads() {
var url;
var jqxhr;
var dat;
url = 'http://' + ip + '/files';
jqxhr = $.getJSON(url, function(dat) {
for(i=0; i<dat.length; i++){
$('#downLoad').append('<p>' + dat[i] + '</p>');
}
$('#bId').append(dat.length);
})
.done(function() {
console.log("OK");
})
.fail(function(data) {
console.log("Fallito: "+data);
})
};
The problem is that when I navigate to the html page that use getDown.js I get the following error on getDown.js
require is not defined
I need to pass the variable that contains the IP address in myapi.js to use it in getDown.js, I hope I explain myself good enough, thanks in advance.
require is global that exists in Node.js code, that is, on the javascript code executing in the server.
Your server will respond to the client and give it an HTML page to render. That HTML page could tell the browser to also request a javascript file from the server. When it receives that file, the client will execute it. The client does not have a require global (you can test it by opening up the console and typing require)
Using Browserify
Or you can write Node-style code, requiring your global like you're doing, but then run the code through browserify. This will create a new javascript bundle that can be executed by the client, so you should tell your html page to use that bundle instead of getDown.js.
Here is a basic example of doing using browserify like this.
module.js
function getIp() {
return 123456;
}
module.exports = {
getIp: getIp
};
main.js
var module = require('./module');
function getIp() {
var ip = module.getIp();
return ip;
};
console.log(getIp());
compile bundle
$ browserify main.js -o public/bundle.js
index.html
<script type="text/javascript" src="public/bundle.js"></script>
Global variable on the client
To use a global variable on the client which is known by the server, you can pass that variable to your rendering engine (possibly Jade if you're using Express) and have it interpolate that variable into a <script> tag which defines some globals. Leave a comment if that's the approach you'd prefer and I can add some more details.
Let me know if you have more questions!

Run the script in node.js only after user select file in html

I am using node.js to launch a serve so that my html can communicate with R code. But I am facing a problem on node.js. In my html page, I have a browse selection button, user can use it to choose the data file they want to read into html and node.js will pass the file name to R, so R code will read data from the selected data file and then run the analytics model. But as i only have very basic knowledge of Node.js, so currently, r code would run only when I open the followling link "localhost:3000/vis/rio". So my question is how to make node.js run the R code in background automatically when the data file has been selected. Thank you very much for your help in advance.
Here are my codes:
Javascript-(sending the file name to node.js):
var dataset,availableTags;
function handleFileSelect(evt) {
var file = evt.target.files[0];
$.ajax({ //getting the file name and update to node.js
type:'post',
url:"/getFileName",
data:{filename:file.name}
});
Papa.parse(file, { //papa is a library I used to read csv file
header: true,
dynamicTyping: true,
complete: function(results) {
dataset=results.data;
}
});
}
$(document).ready(function(){
$("#csv-file").change(handleFileSelect);
});
Node.js script:
serve.js:
var express=require('express');
var path = require('path');
var vis = require('./routes/vis');
var index = require('./routes/index');
var bodyParser=require('body-parser');
var app=express();
require('./routes/main')(app);
app.get('/vis/rio',vis.rio); **//this is a package used to get connection with Rserve**
app.set('views',__dirname + '/views');
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded());
app.post("/getFileName",index.getFileName); **//this is the script to get the file name, it is from index.js**
var server=app.listen(3000,function(){
console.log("Express is running on port 3000");
});
index.js // this is the js file for getting file name
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});
getFileName=function (req,res){
global.filename=req.body.filename; **//this is the global variable which stores the file name**
res.send('true');
};
module.exports = {router:router,getFileName:getFileName};
vis.js // this is the file used to connect with Rserve and pass the name to R code
var rio = require("rio");
var arg={};
exports.rio = function(req, res){
arg={names:[global.filename]};
console.log(arg);
options = {
entryPoint:"nameoffile",
data: arg,
host : "127.0.0.1",
port : 6311,
callback: function (err, val) {
if (!err) {
console.log("RETURN:"+val);
return res.send({'success':true,'res':val});
} else {
console.log("ERROR:Rserve call failed")
return res.send({'success':false});
}
},
}
rio.enableDebug(true);
rio.sourceAndEval(__dirname + "/Rcode/test.R",options);
};
It looks like you aren't calling out to /vis/rio at any point when you make the call out to your server.
You'll either need to make a second call on the client side to /vis/rio or if you want to use that section, you can import/require the module in index.js and include it in getFileName and just call out to the function there before you return the file. I'm not super familiar with rio, but I don't see any access point in your code to that function.
Edit: If I understand what you're trying to do correctly, you can always make a second request (to /vis/rio) in the success callback of your first ajax call.

Express.js and form validation

I'm tring to create a simple node- with express.js script that will sum 3 numbers.
On index I have this:
index.jade
!!! 5
html
head
title Test
body
form(name='form1', method='post', action='/')
label(for='1')
input#1(type='text', name='1')
label(for='2')
input#2(type='text', name='2')
label(for='3')
input#3(type='text', name='3')
input(name='submit', type='button', value='submit')
#result
and also i'm now writing the serverside - app.js with req and res object but how to return a result... also result = 1id + 2id + 3id
app.js
var express = require('express');
app = express.createServer();
app.use(express.bodyParser());
app.post('/', function(req, res){
var i = req.param('1', null);
var j = req.param('2', null);
var k = req.param('3', null);
var r = i+j+k;
res.send(r);
});
How I to send results (r) into div id Result on index.jade... so how to return result to index.jade
also here is pastebin code: http://pastebin.com/J9MRFCaE ... i'm new to node and express and sorry for stupid question...
It's simple, just call your "index.jade" rendering passing your data (instead of 'res.send(r);') :
res.render('index', {
result: r
});
And display "result" variable in your jade file :
#result #{result}
Additional information on jade code and express rendering

Categories