I'm relatively new to node and express, and have come across a problem I can't seem to solve.
I've created a SSCCE which tries to take two inputs, name and height, and if there's a validation error render the same page again with those values.
If I enter '2.2.2' into the height field (obviously not a float), the value is not re-rendered. If I change the height input to type="text", the field is rendered with the previous value. All other fields of type text behave as expected.
I've put 'novalidate' on the form, but is this a quirk with the number input type? Or have I made a simple mistake?
(I'm also slightly confused as to why 'isFloat()' accepts '2' as valid)
Any help would be appreciated
app.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const { check } = require('express-validator/check');
const { validationResult } = require('express-validator/check');
app.use(bodyParser.urlencoded({ extended: false }));
app.set('view engine', 'ejs');
app.set('views', 'views');
app.get('/', (req, res, next) => {
res.render('test', {
pageTitle: 'Test',
hasError: false,
validationErrors: []
})
});
app.post('/',
[
check('name', 'Name must be at least 2 letters in length')
.isLength({min: 3}),
check('height', 'Height must be a float')
.isFloat()
] ,
(req, res, next) => {
const errors = validationResult(req);
if(!errors.isEmpty()){
console.log(errors.array());
return res.render('test', {
pageTitle: 'Error',
hasError: true,
validationErrors: errors.array(),
person: {
name: req.body.name,
height: req.body.height
}
})
} else {
res.send(`Person created: ${req.body.name}, height: ${req.body.height}`);
}
});
app.listen(3000);
test.ejs
<!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><%= pageTitle %></title>
</head>
<body>
<div class="errorMessage"><%= validationErrors.length > 0 ? validationErrors[0].msg:'' %></div>
<form action="/" class="test-form" method="POST" novalidate>
<label for="name">Name</label>
<input type="text" name="name" id="name" value="<%= hasError ? person.name:'' %>">
<label for="height">Height</label>
<input type="number" name="height" id="height" value="<%= hasError ? person.height:'' %>">
<button class="submit">Submit</button>
</form>
</body>
</html>
package.json
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^2.6.1",
"express": "^4.16.4",
"express-validator": "^5.3.1"
}
}
I gave up on this. There didn't seem to be any way to get an input field of type number to submit an invalid value, even with novalidate.
So I just changed the type to text.
Related
Hello i'm new to node js and i am trying send / pass post data to html but i can't seem to get it to work And was hoping maybe someone could point me in the right direction on how i can.
Server code:
const express = require("express");
const bodyParser = require('body-parser');
const app = express();
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/", (request, response) => {
response.sendFile(__dirname + "/views/index.html");
});
app.post('/sendInfo', (req, res) => {
try {
console.log(`firstname: ${req.body.firstname} lastname: ${req.body.lastname}.`);
var firstName = req.body.firstname,
lastName = req.body.lastname;
res.sendFile(__dirname + "/views/info.html", { fistname: firstName, lastname: lastName });
} catch (e) {
console.error("error", e);
}
});
const listener = app.listen(process.env.PORT, () => {
console.log("Your app is listening on port " + listener.address().port);
});
views/info.html code:
<html>
<head>
<title>My Site title</title>
</head>
<body>
<h1><%= fistname %></h1>
<h1><%= lastname %></h1>
</body>
</html>
Looks like you are using the EJS template engine. So, there are a number of things that are missing in your code.
You need to tell express that you are using EJS at the template engine
The view must have an extension of .ejs not .html
You should be using res.render() and pass in the template name and the JSON data which will be used in the template
Set up a Node.js project using npm init -y, then run npm install express ejs, then create the app.js file (code given below) and finally create the views/index.ejs file (code given below). The views directory should be at the same level as your node_modules directory.
// app.js
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 3006;
const app = express();
app.use(express.static(__dirname + '/build'));
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ extended: true }));
app.set('view engine', 'ejs');
app.get('/fn/:first_name/ln/:last_name', (req, res) => {
res.render('index', {
first_name: req.params.first_name,
last_name: req.params.last_name
});
});
app.listen(port, () => {
console.log(`App listening on port ${port}`);
});
// views/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>First name is <%= first_name %></div>
<div>Last name is <%= last_name %></div>
</body>
</html>
Your package.json file must look something like this, use the start script
{
"name": "node-template",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.5",
"express": "^4.17.1"
}
}
Run the app using npm start
Finally, open up a browser and hit http://localhost:3006/fn/John/ln/Doe
If all goes well you will see an html rendered in the browser like this...
First name is John
Last name is Doe
Output:
Good luck.
Note: For the sake of simplicity I used GET instead of POST and used path params instead of request body. But the template engine works the same way.
I am new to Nodejs and trying to use weather api.
When I test the link in browser, it gives me accurate answer
http://api.openweathermap.org/data/2.5/weather?q=karachi&appid=dcf486a78f2b8e898c4b1a464a1b31e1
while it keeps throwing error.
const express = require("express")
var logger = require("morgan")
var path = require("path")
var bodyParser = require("body-parser")
let requested = require('request');
var app=express()
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.set("views", path.resolve(__dirname,"views"))
app.set("view engine",'ejs')
app.use(logger("short"))
app.get("/",function(request,response)
{
response.render("homepage")
})
app.post('/', function(request, response) {
var urlOpenWeatherCurrent = 'http://api.openweathermap.org/data/2.5/weather?'
var queryObject = {
APPID: "dcf486a78f2b8e898c4b1a464a1b31e1",
city: request.body.cityName
}
console.log(queryObject)
requested({
url:urlOpenWeatherCurrent,
q: queryObject // In many tutorials they used 'qs' instead of 'q'. I don't know why.
}, function (err, response, body) {
// response.send('You sent the name ' + request.body.cityName + ".");
if(err){
console.log('error:', error);
} else {
console.log('body:', JSON.parse(body));
}
});
});
app.use(function(request,response)
{
response.status(404)
response.send("Error")
})
app.listen(3000,()=>console.log("Working"))
Error
{ APPID: 'dcf486a78f2b8e898c4b1a464a1b31e1', city: 'karachi' }
'Invalid API key. Please see http://openweathermap.org/faq#error401 for more info.'
If I change q to qs in nodejs, then
{ APPID: 'dcf486a78f2b8e898c4b1a464a1b31e1', city: 'karachi' }
body: { cod: '400', message: 'Nothing to geocode' }
Note that changing q to qs in raw html API link also gives
{"cod":"400","message":"Nothing to geocode"}
I believe from the response that I should use qs in nodejs, because at least this time it is not considering API key wrong. But in the API link, we have q and not qs. So how come qs makes sense? Besides, as far as I Understood, it is not properly concatenating the API strings together, resulting in the malfunctioning. But I don't know how to print the entire link in console to validate what I just said.
views/homepage.ejs
<!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 class="pure-form" action="/" method="POST">
<input type="name" placeholder="City name" name="cityName" autofocus required>
<input type="submit" valuue="Go">
</form>
</body>
</html>
embed the "q" and "api key" with open weather url like "http://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}"
also Check this link
https://codeburst.io/build-a-weather-website-in-30-minutes-with-node-js-express-openweather-a317f904897b
I am making a simple weather application using express and passing the weather info I get from my API to the html file, where I am using ejs to display them.
Here is the file for creating the server:
const express = require("express");
const bodyParser = require("body-parser");
const request = require("request");
const app = express();
const apiKey = "*******************";
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.set("view engine", "ejs");
app.get("/", function (req, res) {
res.render("index", { weather: null, error: null });
});
app.post("/", function (req, res) {
res.render("index");
console.log(req.body.city);
let city = req.body.city;
let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${apiKey}`;
request(url, function (err, response, body) {
if (err) {
res.render('index', { weather: null, error: 'Error, please try again' });
} else {
let weather = JSON.parse(body);
if (weather.main == undefined) {
res.render('index', { weather: null, error: 'Error, please try again' });
} else {
let weatherText = `It's ${weather.main.temp} degrees in ${weather.name}!`;
res.render('index', { weather: weatherText, error: null });
}
}
});
});
app.listen(8080, function () {
console.log("Example app listening on port 8080 !");
});
and here is my html file with ejs :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="/css/style.css" />
</head>
<body>
<h1>Know Your Weather ! </h1>
<div class="container">
<fieldset>
<form action="/" method="POST">
<input name="city" type="text" class="ghost-input" placeholder="Enter a City" required>
<input type="submit" class="ghost-button" value="Get Weather">
</form>
<% if(weather !== null){ %> <p><%= weather %></p><% } %>
<% if(error !== null){ %> <p><%= error %></p><% } %>
</fieldset>
</div>
</body>
</html>
But when I give an input in the website, I get the following error:
> ReferenceError: /home/anirudh/Desktop/weather-app/views/index.ejs:20
> 18| <input type="submit" class="ghost-button" value="Get Weather">
> 19| </form>
> >> 20| <% if(weather !== null){ %> <p><%= weather %></p><% } %>
> 21| <% if(error !== null){ %> <p><%= error %></p><% } %>
> 22| </fieldset>
> 23| </div>
>
> weather is not defined
> at eval (eval at compile (/home/anirudh/Desktop/weather-app/node_modules/ejs/lib/ejs.js:618:12),
> <anonymous>:11:8)
> at returnedFn (/home/anirudh/Desktop/weather-app/node_modules/ejs/lib/ejs.js:653:17)
> at tryHandleCache (/home/anirudh/Desktop/weather-app/node_modules/ejs/lib/ejs.js:251:36)
> at View.exports.renderFile [as engine] (/home/anirudh/Desktop/weather-app/node_modules/ejs/lib/ejs.js:482:10)
> at View.render (/home/anirudh/Desktop/weather-app/node_modules/express/lib/view.js:135:8)
> at tryRender (/home/anirudh/Desktop/weather-app/node_modules/express/lib/application.js:640:10)
> at Function.render (/home/anirudh/Desktop/weather-app/node_modules/express/lib/application.js:592:3)
> at ServerResponse.render (/home/anirudh/Desktop/weather-app/node_modules/express/lib/response.js:1008:7)
> at /home/anirudh/Desktop/weather-app/server.js:17:9
> at Layer.handle [as handle_request] (/home/anirudh/Desktop/weather-app/node_modules/express/lib/router/layer.js:95:5)
What am I doing wrong with the ejs?
The problem is in the post route you define:
app.post("/", function (req, res) {
res.render("index");
// ...
This call to res.render does not provide any locals, and hence, weather is not defined. I haven't tried it, but this immediately caught my eye, and I am pretty sure that this is the source of the error you encounter – especially since you said that it only happens when you submit data.
I assume that this is an unintended leftover of a previous version or some debugging, since you correctly render a few lines below. If you simply remove this call to res.render, I guess that things should work as expected.
I'm using EJS as Template engine. Everything looks like working fine, but I have these weak "Unresolved variable or type data" warnings in IntelliJ. How to get rid of these warnings? Is anything wrong with the code?
app.js:
var express = require('express');
var app = express();
var hostname = 'localhost';
var port = 3000;
app.set('view engine', 'ejs');
app.use('/static', express.static('static'));
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/index.html`);
});
app.get('/profile/:id', (req, res) => {
var userData = {
id: req.params.id,
firstName: 'John',
lastName: 'Peterson',
age: 23,
active: true,
interests: ['Design', 'Web', 'Acting']
};
res.render('profile', { data: userData });
});
app.get('*', (req, res) => {
res.sendFile(`${__dirname}/404.html`);
});
app.listen(port);
console.log(`Server running at http://${hostname}:${port}`);
views/profile.ejs:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My Profile</title>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<h2>My Profile Template</h2>
<p>ID: <%=data.id%></p>
<p>Name: <%=data.firstName%> <%=data.lastName%></p>
<p>Age: <%=data.age%> years</p>
<p>Active: <%=data.active%></p>
</body>
</html>
I solved this problem, by adding spaces between %=%.
<p>Name: <%= data.firstName %> <%= data.lastName %></p>
It looks like you need to export the data object somewhere in your code.
Try to add module.exports = { data: {}; } to the end of your app.js file.
To make autocomplete work correctly, you should either export a real object (userData) instead of an empty one, or use TypeScript.
I try to upload a file to a server using express.js and multer. I cannot get it work, even with a very simple code, it keeps displying the same error :
"TypeError: Cannot read property 'name' of undefined"
I suspect I make some really stupid mistake, yet I cannot find out what's the problem. Thank you very much for your help !
index.html :
<!doctype html>
<html>
<head>
<title>File upload test</title>
</head>
<body>
<form id="uploadform" method="post" action="/upload" enctype="multipart/form-data">
<p><input type="file" name="img"></p>
<p><input id="submit_upload" type="submit" value="Submit"></p>
</form>
</body>
</html>
and on the server side (server.js)
var express = require('express');
var app = express();
var multer = require('multer');
var upload = multer({ dest: 'uploads/' })
app.get('/', function(req, res){
res.sendfile(__dirname + '/client/index.html');
});
app.post('/upload', upload.single('img'), function (req, res) {
//var form_description = req.body.description;
console.log(req.files.name);
// insert operations into database get placed here
res.redirect('/');
});
package.json :
{
"name": "upload-example",
"version": "0.0.0",
"description": "A file upload example",
"main": "server.js",
"repository": "",
"author": "",
"dependencies": {
"async": "~0.2.8",
"express": "^3.2.6",
"multer": "^1.1.0",
"socket.io": "~0.9.14"
}
}
1) You configure multer to accept single file, and single file will be stored in req.file.
2) Original filename stored in req.file.originalname.
3) Temp filename stored in req.file.filename.