I have been following this tutorial on building a web app and database using node.js, express and jade.
https://cozy.io/en/hack/getting-started/first-app.html
Despite laying out everything the same, my index.jade is not loading on localhost. There are no errors to suggest why on browser terminal. I have checked that my environment variables are set up, and I have altered the filepaths to index.jade, but it has not made any difference, just a white screen. On my command prompt, the server is listening and the database is connected.
My environment folder is
C:\foodshop and within this I have
node_modules,
index.jade,
package.json,
shopDB.db,
simpleserver.js
simpleserver.js contains the following -
// This is the server.
var http = require('http'),
express = require('express'),
app = express(),
sqlite3 = require('sqlite3').verbose(),
db = new sqlite3.Database('shopDB.db', (function(err) {
if (!err) {
console.log("Database is connected ... \n\n");
} else {
console.log("Error connecting database, check for shopDB.db file... \n\n");
}
}));
/* We add configure directive to tell express to use Jade to
render templates */
app.get('env', (function() {
app.set('views', __dirname + '');
app.engine('.html', require('jade').__express);
// Allows express to get data from POST requests
app.use(express.bodyParser());
}));
// Database initialization (First list names of tables and check if currently exists.)
db.get("SELECT name FROM sqlite_master WHERE type='table' AND name='itemList'", function(err, row) {
if (err !== null) {
console.log(err);
} else if (row == null) {
db.run('CREATE TABLE IF NOT EXISTS "itemList" ("ID" INTEGER PRIMARY KEY NOT NULL, "itemName" VARCHAR(100) NOT NULL, "itemWeight" INT(5) NOT NULL, "expiryDate" DATE, "itemPrice" double DEFAULT NULL)', function(err) {
if (err !== null) {
console.log(err);
} else {
console.log("SQL Table 'itemList' initialized.");
}
});
} else {
console.log("SQL Table 'itemList' already initialized.");
}
});
// We render the templates with the data
app.get('/', function(req, res) {
db.all('SELECT * FROM itemList ORDER BY itemName', function(err, row) {
if (err !== null) {
res.send(500, "An error has occurred -- " + err);
} else {
//res.sendfile('./public/index.html')
res.render('./index.jade', {
itemList: row
}, function(err, html) {
//res.sendfile('./index.jade')
//res.send(200, html);
res.status(200).send(html);
});
}
});
});
// We define a new route that will handle item creation
app.post('/add', function(req, res) {
ID = req.body.ID;
itemName = req.body.itemName;
itemWeight = req.body.itemWeight;
expiryDate = req.body.expiryDate;
itemPrice = req.body.itemPrice;
sqlRequest = "INSERT INTO 'itemList' (ID, itemName, itemWeight, expiryDate, itemPrice) VALUES('" + ID + "', '" + itemName + "', '" + itemWeight + "', '" + expiryDate + "', '" + itemPrice + "')"
db.run(sqlRequest, function(err) {
if (err !== null) {
res.send(500, "An error has occurred -- " + err);
} else {
res.redirect('back');
}
});
});
// We define another route that will handle item deletion
app.get('/delete/:itemName', function(req, res) {
db.run("DELETE FROM itemList WHERE itemName='" + req.params.itemName + "'", function(err) {
if (err !== null) {
res.send(500, "An error has occurred -- " + err);
} else {
res.redirect('back');
}
});
});
/* This will allow Cozy to run your app smoothly but
it won't break other execution environment */
var port = process.env.PORT || 9250;
var host = process.env.HOST || "127.0.0.1";
// Starts the server itself
var server = http.createServer(app).listen(port, host, function() {
console.log("Server listening to %s:%d within %s environment",
host, port, app.get('env'));
});
And this is the index.jade file
doctype 5
html(lang="en")
head
title Items
body
form(action="add", method="post")
label ID:
input(type="text", name="ID")
label itemName:
input(type="text", name="itemName")
label itemWeight:
input(type='text', name='itemWeight')
label expiryDate:
input(type='text', name='expiryDate')
label itemPrice:
input(type='text', name='itemPrice')
input(type="submit", value="Add a new item")
ul
- for(item in itemList) {
li
a(href=itemList[item].url)= itemList[item].itemName
| - (
a(href="delete/#{itemList[item].id}") delete
| )
- }
I followed that same tutorial and got to the part where they start with the Jade template and had the exact same problem you did. I backed up a little bit, and grabbed the example template from the Jade website, and it worked fine. I changed Cozy's "bookmark" template a little bit and got it working. You might try this:
doctype html
That different doctype made a difference in my example. I'm not an expert on Jade, but I'd definitely try that and see if you have any luck.
Edit: After looking a bit further, it looks like doctype 5 is deprecated, and doctype html is recommended now.
Another Edit: If you're still having issues with your view rendering, I'd do two things. One, I'd check the tutorial out, match their jade view with yours, and start adding things one at a time until it breaks to narrow down the issue. Two, I'd change:
app.get('env', (function() {
app.set('views', __dirname + '');
app.engine('.html', require('jade').__express);
// Allows express to get data from POST requests
app.use(express.bodyParser());
}));
to
app.set('views', __dirname + '');
app.engine('.html', require('jade').__express);
// Allows express to get data from POST requests
app.use(express.bodyParser());
You don't appear to be using the env. variables, and I don't see any reason to move your view renderer setup inside that. Move it to the top (like in the example) and see if that works for you.
Related
I am studying about very basic Serverside JS using express, jade, node.JS.
At the first page (localhost/topic), there is a list. And List's data from MySQL.
(MySQL fields are id, title, description, and author)
Also, there is a link to open the form (the form is in add.jade file) that can add an item on the list.
My problem is that if I clicked the link, the page still shows the view.jade. But, the address is changed to "localhost/topic/add".
I've checked the "app.js" file to see if app.get() isn't set appropriately. But I did not find any.
Actually, the template was written as jade at first. But I tried to convert jade to pug. After this error, I put them back all to jade.
Is that a problem?
Thank you.
var express = require("express");
var app = express();
app.set("views", "./views_mysql");
app.set("view engine", "jade");
app.listen(3000, function() {
console.log("Connected, 3000 port!");
});
app.locals.pretty = true;
var mysql = require("mysql");
var conn = mysql.createConnection({
host: "localhost",
user: "jimin",
password: "****",
database: "o2"
});
conn.connect();
app.get(["/topic", "/topic/:id"], function(req, res) {
var sql = "SELECT id, title FROM topic";
conn.query(sql, function(err, topics, fields) {
var id = req.params.id;
if (id) {
var sql = "SELECT * FROM topic WHERE id=?";
conn.query(sql, [id], function(err, id_topics, fields) {
if (err) {
console.log(err);
res.status(500).send("Internal Server Error");
} else {
res.render("view", { topics: topics, topic: id_topics[0] });
}
});
} else {
res.render("view", { topics: topics });
}
});
});
app.get("/topic/add", function(req, res) {
var sql = "SELECT id, title FROM topic";
conn.query(sql, function(err, topics, fields) {
if (err) {
console.log(err);
res.status(500).send("Internal Server Error");
} else {
res.render("add", { topics: topics });
}
});
});
<!-- begin snippet: js hide: false console: true babel: false -->
// add.jade
doctype html
html
head
meta(charset='utf-8')
body
h1
a(href='/topic') Server Side JavaScript
ul
each topic in topics
li
a(href='/topic/' + topic.id)= topic.title
article
form(action='/topic/add' method='post')
p
input(type='text' name='title' placeholder='title')
p
textarea(name='description' placeholder='description')
p
input(type='text' name='author' placeholder='author')
p
input(type='submit')
//view.jade
doctype html
html
head
meta(charset='utf-8')
body
h1
a(href='/topic') Server Side JavaScript
ul
each topic in topics
li
a(href='/topic/' + topic.id)= topic.title
article
if topic
h2= topic.title
= topic.description
div= 'by ' + topic.author
else
h2 Welcome
| This is Server Side JS Tutorial
div
a(href='/topic/add') add Topic
app.get("/topic/add", function(req, res) {
var sql = "SELECT id, title FROM topic";
conn.query(sql, function(err, topics, fields) {
if (err) {
console.log(err);
res.status(500).send("Internal Server Error");
} else {
res.render("add", { topics: topics });
}
});
});
This is an issue with the arrangement of the routes.
TLDR
Move the route definition of app.get above the previously declared route.
Explanation
Route definitions in express are from a top-to-bottom approach. So, in runtime, your routes are seen as follows:
/topic
/topic/:id
topic/add
When you visit the page /topic/add, you would expect it to match to the third on the list but Express actually matches it to the second on the list... It will actually match everything if you put anything after /topic.
I am building a VERY basic application to book a vehicle for hire, I am trying to access data from mongodb, which seems to work, as it outputs to the console on load. I cannot get this information to render in my view. If I set the render method outside of the function scope I cannot access the db data, if I set the render inside then the booking page never loads. I have been messing around with the same block of code for days now and I have had no joy.
//------------------------------------------------THE SET UP--------------------------------------------
// set node dependencies
let express = require("express");
let bodyParser = require("body-parser");
let mongoose = require("mongoose");
let connection = mongoose.connection;
let data = mongoose.connect("mongodb://localhost:27017/test")
// allow for encoding od POST DATA
let urlencodedParser = bodyParser.urlencoded({extended: false});
// set up app to extend express
let app = express();
// view engine
app.set("view engine", "ejs");
// static files
app.use("/assets", express.static("assets"));
//------------------------------------------------------------------------------------------------------
// REDIRECTS BASED ON URL
app.get('/', function(req,res){
res.render("index")
});
app.get('/booking', function(req,res){
res.render("booking",{qs:req.query})
});
app.post('/booking',urlencodedParser, function(req,res){
// Surround this with if !blacklisted to run inner code
if (req.body.blacklist !== "on"){
console.log(req.body);
// booking page takes age details and redirects/queries database accordingly
if (req.body.age >= 25){
connection.once('open', function () {
connection.db.collection("vehicles", function(err, collection){
collection.find({}).toArray(function(err, data){
console.log(data[0]._id); // it will print collection data
})
});
res.render("contact-success",{data:req.body})
connection.close();
});
}
else if (req.body.age < 25 && req.body.age > 17){
connection.once('open', function () {
connection.db.collection("vehicles", function(err, collection){
collection.find({}).toArray(function(err, data){
console.log(data[0]._id + "<25 message"); // it will print collection data
})
})
})
// THIS IS WHERE I WANT TO PASS THE DB DATA INTO.. so that it redirects to this page and filters the vehicles collection appropriately.
res.render("contact-failed",{data:req.body});
}
}
else{
console.log(req.body.firstName , req.body.lastName , "Has been blacklisted!")
res.render("blacklisted",{data:req.body});
}
// else if blacklisted redirect to a sorry, contact company page.
});
let port = 3000;
app.listen(port);
console.log("listening on port " + port);
Few things about your code -
You should call res.render() inside the call to mongodb.
connection.once('open', function () {
connection.db.collection("vehicles", function(err, collection){
collection.find({}).toArray(function(err, data){
console.log(data[0]._id); // it will print collection data
res.render("contact-success",{data:req.body})
});
});
connection.close();
});
You are not checking for errors. If you get any error with query, you will end up with no response to the request. So it's always better to check for errors.
if(err) {
// process the error and send appropriate message.
} else {
// send what you want to send to view.
res.render("contact-success",{data:req.body})
}
You have conditions for
if (req.body.age >= 25){
...
} else if (req.body.age < 25 && req.body.age > 17){
...
}
But there is nothing for plain else. So if any of the two conditions is not met, you will end up with no response to the request.
There should be one res.render() or res.send() in each of the conditions.
I'm relatively new to using Node.js. I've successfully created an app that takes user data (specifically the date in which the user was created) and spits out the amount of daily, weekly, monthly and yearly users. This was successfully tested via Postman.
I've successfully installed pugjs and am trying to transfer the calculated data in to the pug file. I have a controller, model and route file all represented below:
userAPIController.js
'use strict';
const mongoose = require('mongoose'),
express = require('express'),
app = express(),
moment = require('moment'),
pug = require('pug'),
User = mongoose.model('Users'),
compiledFunction = pug.compile('results.pug');
exports.list_all_users = function(req, res) {
User.find({}, function(err, user) {
if (err)
res.send(err);
res.json(user);
});
};
exports.create_a_user = function(req, res) {
var new_task = new User(req.body);
new_task.save(function(err, user) {
if (err)
res.send(err);
res.json(user);
});
};
exports.calculate = function(req, res) {
User.find({}, function(err, userArray) { //the second parameter, userArray, is an array that is returned to you.
if (err)
res.send(err);
var daily_count = 0;
var weekly_count = 0;
var monthly_count = 0;
var yearly_count = 0;
var total_count = 0;
for (var i = 0; i < userArray.length; i++) {
total_count++;
var timeString = userArray[i].Created_date;
var dayString = timeString.getUTCDate();
var monthString = timeString.getUTCMonth()+1;
var yearString = timeString.getUTCFullYear();
var todaysDate = new Date();
var todaysDay = todaysDate.getUTCDate();
var todaysMonth = todaysDate.getUTCMonth()+1;
var todaysYear = todaysDate.getUTCFullYear();
// Calculating Daily Users
if (dayString === todaysDay && monthString === todaysMonth && yearString === todaysYear) {
daily_count += 1;
}
// Calculating Weekly Users
var weekDifference = todaysDay - dayString;
if (monthString === todaysMonth && yearString === todaysYear && (weekDifference >= 0 && weekDifference <= 7)) {
weekly_count += 1;
}
// Calculating Monthly Users
if (monthString === todaysMonth && yearString === todaysYear) {
monthly_count += 1;
}
// Calculating Yearly Users
if (yearString === todaysYear) {
yearly_count += 1;
}
}
res.json({
"daily_count":daily_count,
"weekly_count":weekly_count,
"monthly_count":monthly_count,
"yearly_count":yearly_count,
"total_count":total_count
});
});
};
exports.delete_a_user = function(req, res) {
User.remove({
_id: req.params.userId
}, function(err, user) {
if (err)
res.send(err);
res.json({ message: 'User successfully deleted' });
});
};
With a userAPIModel.js, userAPIRoutes.js and server.js file as well, all modeled after this tutorial: https://www.codementor.io/olatundegaruba/nodejs-restful-apis-in-10-minutes-q0sgsfhbd
I also have a views folder with the pug file inside, and am unsure how to take my daily, weekly, monthly and yearly users (as seen in the controller) and transfer them in to the pug. I understand the #{} pug syntax; however I am not sure about how to get the information over. I've tried going in to the controller file where the data is located and using a res.send function such as:
app.get('/', function (req, res) {
res.send(compiledFunction({
dCount: daily_count,
wCount: weekly_count,
mCount: monthly_count,
yCount: yearly_count,
tCount: total_count
}));
})
And then importing it to pug from there. The only concern is, I don't believe this is the correct way to link the controller to the pug file or that I'm using the right function.
What exactly am I doing wrong? I figure I'd put the above in the controller because that's where the JSON is being outputted, but I'm used to putting it in the server file.
I love pug. You probably will, too.
Step 1) At some point after you require pug, and before you start routing, set pug as the view engine.
var app = express();
app.set('view engine', 'pug');
Step 2) Make a views folder in your project root and write a pug template in there. I.E. /project_root/views/home.pug
Step 3) route a request to your template. This is done by using the express method "render". You can attach variables or function results to the data object. In my example, I'm literally calling it "data" but you can reference it however you want so long as it's a javascript object. The key names are important as they're used to reference your data in the pug template.
app.route('/', function(req, res){
res.render('home.pug', {data: someVar});
});
Step 4) Reference your data in your template. Pug allows you to not just reference, but you can iterate over it or perform JavaScript on it. A simple example of what "home.pug" might look like is this:
doctype
html
head
title Test Template
body
// Here it's interpolated in a string
h1 Take a look at my #{data}
// Here the inner html is being set as your variable
h2= data
// Here's an example of your data being set to a tag attribute value using ES6 template strings
a(href=`${data}`) Click Here
Add this to your bookmarks for future reference:
https://expressjs.com/en/guide/using-template-engines.html
Be sure to read up more on pug here:
https://pugjs.org/api/getting-started.html
I was recently working on a javascript that uses socket.io,node.js and express.js.
here is the server code.
var
port = +process.argv[2] || 8080,
sanitizer = require('validator').sanitize,
express = require('express'),
server = express.createServer(),
io = require('socket.io').listen(server),
chat = io.of('/chat'),
canvas = io.of('/canvas')
;
function sanitize(string) {
return sanitizer(string).entityDecode()
}
server.listen(port);
server.get(/(^\/.*$)/, function(request, response) {
var fileName = request.params[0];
if (fileName == '/')
fileName = '/index.html';
response.sendfile(__dirname + '/client' + fileName);
});
io.sockets.on('connection', function(socket) {
socket.on('setName', function (name) {
name = sanitize(name);
socket.set('name', name);
socket.broadcast.emit('receive', {
sender:'Server',
message:name + ' has joined.'
})
});
socket.on('send', function (message) {
socket.get('name', function(error, name) {
if (name)
socket.broadcast.emit('receive', {
sender:name,
message:sanitize(message)
})
})
});
socket.on('draw', function (command) {
io.sockets.emit('draw', command)
});
socket.on('updateCursor', function(position) {
socket.get('name', function(error, name) {
if (name)
socket.broadcast.emit('updateCursor', {
name:name,
position:position
});
});
});
socket.on('disconnect', function() {
socket.get('name', function(error, name) {
if (name) {
socket.broadcast.emit('receive', {
sender:'Server',
message:name + ' has left.'
});
socket.broadcast.emit('removeCursor', name);
}
})
});
});
I am able to set up the server successfully, but when I use the localhost on the browser, I get the following error:
TypeError: Path must be a string. Received null
at assertPath (path.js:8:11)
at win32.join (path.js:221:5)
at exports.send (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\node_modules\connect\lib\middleware\static.js:127:20)
at ServerResponse.res.sendfile (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\lib\response.js:186:3)
at C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\server.js:23:14
at callbacks (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\lib\router\index.js:272:11)
at param (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\lib\router\index.js:246:11)
at pass (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\lib\router\index.js:253:5)
at Router._dispatch (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\lib\router\index.js:280:5)
at Object.Router.middleware [as handle] (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\lib\router\index.js:45:10)
I had developed this using the unstable v0.5.8 windows binary version of node.
but I am currently running the 4.4.5 version.
Please help me, where did I go wrong?
It's a little difficult to tell from the sample code you've pasted because your stack trace references line 45 in your index.js as the source of the problem (C:\Users\Akshay\Desktop\whiteboard-master\whiteboard-master\node_modules\express\lib\router\index.js:45:10) but when I look at your sample/pasted code in an IDE, it's not doing anything there. The only call to sendfile (referenced further up in your stack trace) is earlier in the script.
Assuming that's the location of your issue, you should console.log() or otherwise debug the value of the path/filename you're attempting to send to the visitor. Note that in Windows, path delimiters are \ not /. You should use path.join() to form the final path to the file served. The ExpressJS examples illustrate this:
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname, 'index.html'));
});
I am trying to use nodejs and mongodb. I can enter tweets to a collection with using a function of ntwitter
twit.stream('statuses/filter', {'track':'dio'}, function(stream) {
stream.on('data', function (data) {
var tweet = data.text;
tweetCollection.insert(tweet,function(error){
if(error) {
console.log("Error", error.message);
} else {
console.log("Inserted into database");
}
});
});
});
When I try to get the tweets from the collection I use express , nodejs and mongo and use them as below :
app.get('/', function(req, res){
var content = fs.readFileSync("template.html");
getTweets(function(tweets){
console.log(tweets);
var ul = '';
tweets.forEach(function(tweet){
ul +='<li><strong>' + ":</strong>" + tweet["text"] + "</li>";
});
content = content.toString("utf8").replace("{{INITIAL_TWEETS}}", ul);
res.setHeader("Content-Type", "text/html");
res.send(content);
});
});
db.open(function(error) {
console.log("We are connected " + host + ":"+ port);
db.collection("tweet",function(error, collection){
tweetCollection = collection;
});
});
function getTweets(callback) {
tweetCollection.find({}, { "limit":10, "sort":{"_id":-1} } , function(error, cursor){
cursor.toArray(function(error, tweets){
callback(tweets);
});
});
};
In the console.log I see tweets as in this pastebin link
In the browser I get an unordered list of
:undefined
:undefined
What can I do to show tweets text ?
Thanks
You're not storing the entire tweet object, just the text. So the mongodb driver sees your string as an array, hence the array-like object properties you're seeing.
Try this line:
tweetCollection.insert(data,function(error){
instead of:
tweetCollection.insert(tweet,function(error){
Or if you really just want to store the text, try something like:
tweetCollection.insert({ text: tweet },function(error){