Using Each Loop in EJS Template and Express JS - node.js

I am working on a form validation and i am trying to loop the errors in my template but i keep getting error.
In my posts routes i have this
router.post('/create', async (req, res)=>{
try{
var errors = [];
if(!req.body.title){
errors.push({message: 'Please Add a Title'})
}
if(errors.length > 0){
res.render('admin/posts/create',{errors: errors})
} else{
let filename = 'Nissan.jpeg';
if(!isEmpty(req.files)){
const file = req.files.file
filename = Date.now() + '-' + file.name
file.mv('./public/uploads/' + filename, (err)=>{
if(err) throw err
})
}
let allowComments = true;
if(req.body.allowComments){
allowComments = true;
} else{
allowComments = false;
}
const newPost = await new Post({
title: req.body.title,
status: req.body.status,
allowComments: allowComments,
body: req.body.body,
file: filename
});
const savedPost = await newPost.save();
// console.log(savedPost);
res.redirect('/admin/posts');
}
} catch (error){
console.log(error);
}
});
And in my ejs template with url (admin/posts/create) i have this
<% errors.forEach(errors => { %>
<%-errors.message %>
<% }) %>
But i keep getting this error message in my browser
ReferenceError: /blog/views/admin/posts/create.ejs:2
1| <%- include('../admin-partials/head') %>
>> 2| <% errors.forEach(error => { %> <%-error.message %> <% }) %>
3| <div class="dashboard-col-2">
4| <h1>Create Post</h1>
5|
errors is not defined
What can i do to solve this error message?
When i do console.log(errors) i get this
[{ message: 'Please Add a Title' } ]

if(errors.length > 0){
res.render('admin/posts/create',{errors: errors})
You are only rendering errors if it's > 0, otherwise it's undefined.

Related

Getting "TypeError: Cannot read properties of null (reading 'items')" error but the code works after reloading

so I was working on making this Todo list website but I am facing a problem.
NODE.JS CODE:
//jshint esversion:6
// _______________________________Database Code_________________________________
const mongoose = require("mongoose")
none = []
main().catch(err => console.log(err));
async function main() {
mongoose.set('strictQuery', false);
await mongoose.connect('mongodb://0.0.0.0:27017/todolistDB');
}
// For the main list
const itemSchema = {
itemName: {
type: String,
required: true
}
}
const Item = mongoose.model("Item", itemSchema)
const buyFood = new Item({
itemName: "Buy Food"
})
const cookFood = new Item({
itemName: "Cook Food"
})
const eatFood = new Item({
itemName: "Eat Food"
})
const defaultItems = [buyFood, cookFood, eatFood]
// New list schema
const listSchema = {
listName: String,
items: [itemSchema]
}
const List = mongoose.model("list", listSchema)
// Function that creates new lists
function makeNewList(name) {
const list = new List({
listName: name,
items: defaultItems
})
list.save()
}
// Function that creates new list items
function createNewItem(newItem) {
const item = new Item ({
itemName: newItem
})
}
// Function to find a list
function findList(listName) {
List.findOne({listName: listName}, function(err, list) {
if (!err) {
return list
}
})
}
// _______________________________Server Code___________________________________
const express = require("express");
const bodyParser = require("body-parser");
const date = require(__dirname + "/date.js");
const _ = require("lodash")
const popup = require("node-popup")
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static("public"));
const workItems = [];
// Default Home List
app.get("/", function(req, res) {
const day = date.getDate();
Item.find(function(err, item) {
if (item.length === 0) {
Item.insertMany(defaultItems, function(err) {
if (err) {
console.log(err);
} else {
console.log("Items added successfully.");
}
})
}
else if (err) {
console.log(err);
}
else {
List.find({}, function(err, list) {
if (err) {
console.log(err);
}
else if (list.length === 0) {
res.render("list", {listTitle: day, newListItems: item, array: none});
}
else {
list.forEach(function(listName) {
console.log(listName);
})
res.render("list", {array: list, newListItems: defaultItems, listTitle: day})
}
})
}
})
});
// Creating new list items
app.post("/", function(req, res){
const item = req.body.newItem;
const listName = req.body.list;
if (listName === "day") {
createNewItem(item)
res.redirect("/")
}
// else {
// List.findOne({listName: listName}, function(err, foundList) {
// foundList.items.push(item)
// foundList.save()
// res.redirect("/" + listName)
// })
// }
});
// Deleting list items
app.post("/delete", function(req, res) {
deletedItem = String(req.body.box)
Item.deleteOne({_id: deletedItem}, function(err) {
if (err) {
console.log(err);
} else {
console.log("Item deleted successfully");
}
})
res.redirect("/")
})
// Making new lists
app.post("/list", function(req, res) {
newList = req.body.newListName.toLowerCase()
List.findOne({listName: newList}, function(err, listInSearch) {
if (!listInSearch) {
console.log("Does not exist");
makeNewList(newList)
res.redirect("/" + newList)
}
else {
console.log("Exist");
}
})
})
// Loading existing list
app.get("/:extension", function(req, res) {
extension = req.params.extension.toLowerCase()
console.log("Site ends with " + extension);
if (extension !== "list") {
List.find({}, function(err, list) {
if (err) {
console.log(err);
}
else {
List.findOne({listName: extension}, function(err, foundList) {
if (!err) {
items = foundList.items
console.log(items);
res.render("list", {array: list, newListItems: foundList.items, listTitle: _.startCase(extension)})
}
})
}
})
}
})
// app.post("/:extension", function(req, res) {
// extension = req.params.extension.toLowerCase()
// item = req.body.newItem.toString()
//
// console.log(item);
// console.log(extension);
//
// List.findOne({listName: extension}, function(err, foundList) {
// if (!err) {
// createNewItem(item)
// foundList.items.push(item)
// foundList.save()
// res.redirect("/" + extension)
// }
// })
// })
// About page
app.get("/about", function(req, res){
res.render("about");
});
// Server port
app.listen(2000, function() {
console.log("Server started on port 2000");
});
HTML CODE:
<%- include("header") -%>
<!-- Showing list title -->
<div class="content">
<div class="box" id="heading">
<h1> <%= listTitle %> </h1>
</div>
<!-- Showing all lists -->
<div class="form">
<div class="btn-group">
<button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Lists
</button>
<ul class="dropdown-menu">
<% array.forEach(function(item) {%>
<li><a class="dropdown-item" href="/<%= item.listName %>"> <%= item.listName %> </a></li>
<% }) %>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="/">Default List</a></li>
</ul>
</div>
<!-- Making new lists -->
<div class="list drop">
<form action="/list" method="post">
<input type="text" name="newListName" placeholder="New List Name" autocomplete="off">
<button class="btn btn-primary btn-md" type="submit" name="newList">Create</button>
</form>
</div>
</div>
<!-- Showing each list item -->
<div class="box">
<% newListItems.forEach(function(item) {%>
<form class="form-group" action="/delete" method="post">
<div class="item">
<input type="checkbox" onChange="this.form.submit()" name="box" value="<%= item._id %>">
<p><%= item.itemName %></p>
</div>
</form>
<% }) %>
<!-- Adding new list items -->
<form class="item" action="/" method="post">
<input type="text" name="newItem" placeholder="New Item" autocomplete="off">
<button class="button" type="submit" name="list" value="<%= listTitle %>">+</button>
</form>
</div>
</div>
<%- include("footer") -%>
Now, the website works well for the home page but I have added the functionality to make custom lists with custom names and that's where the issue arises. Whenever I make a new list, I want to add some items to it that are then stored in mongodb database. But if you look at the "Loading existing list" section of the .js code, there's the "newListItems" parameter which is supposed to take a list of items which are later displayed on the screen using a forEach() loop in the html document using EJS. Now, I have checked it multiple times, the items always get added to the database and exist there but when it's time to render them, the "foundList.items" gives that "TypeError: Cannot read properties of null (reading 'items')" error. I don't know what to do... And one more thing, when I try to create a new list after already creating one before, the second one doesn't gets any issues whatsoever. No idea what that is but it only happens the first time.
I hope someone can help...

NodeJS render html file with form not working on angular side

I am using ExpressJS with EJS template view engine. I am trying to show an HTML file on the angular component, but the form tag and its child input tag do not work on the angular side. They show only label data.
On NodeJS
agreementController.js
exports.getAgreementHtml = async (request, response, next) => {
const params = request.query
let reqPath = path.join(__dirname, '../agreements');
var agreementObj = {
user: { email: "example#gmail.com" }
}
// render domestic rent html
ejs.renderFile(reqPath + '/domestic_rent.ejs', agreementObj, {}, function (err, str) {
if (err !== null) {
responseObj.status = errorCodes.DATA_NOT_FOUND
responseObj.message = language.getMessage('NO_RECORD_FOUND')
response.send(responseObj)
return
}
responseObj.status = errorCodes.OK
responseObj.data = str
response.send(responseObj);
return;
});
}
domestic_rent.js
<form>
<div class="form-group">
<p><%= user.email %></p>
<div class="col-sm-offset-2 col-sm-10">
<input type="text" class="form-control" id="inputEmail3" placeholder="test" required name="test">
</div>
</div>
</form>
On Angular 8 Side
agreement-show.component.ts
getAgreementData() {
const params = {
id: this.agreementId
};
this.agreementService.getAgreementHtml(params).subscribe(
(result) => {
console.log('result agreement data::: ', result);
if (result.status !== 200) {
this.commonService.change.emit({ status: 'error', message: 'unknown error' });
return;
}
this.someHtml = result.data;
return;
}, (error) => {
console.log('error', error)
this.commonService.change.emit({ status: 'error', message: error.message });
}
);
}
agreement-show.component.html
<div [innerHTML]="someHtml"></div>
Output Attachment
By using ElementRef function we can add html runtime.
Please use following step:
#ViewChild('showitems') showitems: ElementRef;
const elemt: HTMLElement = this.showitems.nativeElement;
this.someHtml = result.data;
elemt.innerHTML = this.someHtml;

How to insert and retrieve video from mongodb in node js

I new to mean stack. I want to upload video to mongodb and then I want to retrieve it.
this is app.js file
`const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const crypto = require('crypto');
const mongoose = require('mongoose');
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
const Grid = require('gridfs-stream');
const methodOverride = require('method-override');
const app = express();
// Middleware
app.use(bodyParser.json());
app.use(methodOverride('_method'));
app.set('view engine', 'ejs');
// Mongo URI
const mongoURI = 'mongodb://fawad:Fawad123#ds155243.mlab.com:55243/imageupload';
// Create mongo connection
const conn = mongoose.createConnection(mongoURI);
// Init gfs
let gfs;
conn.once('open', () => {
// Init stream
gfs = Grid(conn.db, mongoose.mongo);
gfs.collection('uploads');
});
// Create storage engine
const storage = new GridFsStorage({
url: mongoURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString('hex') + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: 'uploads'
};
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage });
// #route GET /
// #desc Loads form
app.get('/', (req, res) => {
gfs.files.find().toArray((err, files) => {
// Check if files
if (!files || files.length === 0) {
res.render('index', { files: false });
} else {
files.map(file => {
if (
file.contentType === 'video/mp4' ||
file.contentType === 'video/webm '
) {
file.isVideo = true;
} else {
file.isVideo = false;
}
});
res.render('index', { files: files });
}
});
});
// #route POST /upload
// #desc Uploads file to DB
app.post('/upload', upload.single('file'), (req, res) => {
// res.json({ file: req.file });
res.redirect('/');
});
// #route GET /files
// #desc Display all files in JSON
app.get('/files', (req, res) => {
gfs.files.find().toArray((err, files) => {
// Check if files
if (!files || files.length === 0) {
return res.status(404).json({
err: 'No files exist'
});
}
// Files exist
return res.json(files);
});
});
// #route GET /files/:filename
// #desc Display single file object
app.get('/files/:filename', (req, res) => {
gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
// Check if file
if (!file || file.length === 0) {
return res.status(404).json({
err: 'No file exists'
});
}
// File exists
return res.json(file);
});
});
// #route GET /image/:filename
// #desc Display Image
app.get('/video/:filename', (req, res) => {
gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
// Check if file
if (!file || file.length === 0) {
return res.status(404).json({
err: 'No file exists'
});
}
// Check if image
if (file.contentType === 'video/mp4' || file.contentType === 'video/webm') {
// Read output to browser
const readstream = gfs.createReadStream(file.filename);
readstream.pipe(res);
} else {
res.status(404).json({
err: 'Not an image'
});
}
});
});
// #route DELETE /files/:id
// #desc Delete file
app.delete('/files/:id', (req, res) => {
gfs.remove({ _id: req.params.id, root: 'uploads' }, (err, gridStore) => {
if (err) {
return res.status(404).json({ err: err });
}
res.redirect('/');
});
});
const port = 9000;
app.listen(port, () => console.log(`Server started on port ${port}`));
`
index.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">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<style>
video {
width: 100%;
}
</style>
<title>Mongo File Uploads</title>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 m-auto">
<h1 class="text-center display-4 my-4">Mongo File Uploads</h1>
<form action="/upload" method="POST" enctype="multipart/form-data">
<div class="custom-file mb-3">
<input type="file" name="file" id="file" class="custom-file-input">
<label for="file" class="custom-file-label">Choose File</label>
</div>
<input type="submit" value="Submit" class="btn btn-primary btn-block">
</form>
<hr>
<% if(files){ %>
<% files.forEach(function(file) { %>
<div class="card card-body mb-3">
<% if(file.isVideo) { %>
<video src="video/<%= file.filename %>" alt="">
<% } else { %>
<%= file.filename %>
<% } %>
<form method="POST" action="/files/<%= file._id %>?_method=DELETE">
<button class="btn btn-danger btn-block mt-4">Delete</button>
</form>
</div>
<% }) %>
<% } else { %>
<p>No files to show</p>
<% } %>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</body>
</html>
this code work for image..when I used (file.contentType = image/png).
but for video it's not working.. is Image and video upload are same?
You can use Formidable. As It support multipart data. And for retrieve video you can use fs(file system)
Actually you don't save media(image or video) in DB, you store it in some storage drive(locally or cloud) like s3 bucket, and then store its location url in your DB.
and this code might be helpful.
saveImage(urlPath, folderPath, multiple) {
return new Promise((resolve, reject) => {
var timestamp = Date.now();
var filepath = urlPath;
var imageUrl;
var ext = path.extname(filepath || '').split('.');
var extension = ext[ext.length - 1];
var tmp_path = filepath;
imageUrl = folderPath + timestamp + '.' + extension;
if (multiple != '' && multiple != undefined) { imageUrl = folderPath + timestamp + multiple + '.' + extension; }
var target_path = __dirname + '/../' + imageUrl;//Change according to your location.
console.log("target_path", target_path);
mv(tmp_path, target_path, { mkdirp: true }, function (err) { })
return resolve({ status: 1, url: imageUrl });
})
}
Now, urlPath is your media path, foldarPath is path where you want to store your media and multiple is to give unique name.
you can call this method like this.
var multiple = Number(0) + Number(10);
console.log("multiple", multiple);
var saveImage = await 'YOUR_FILE_NAME'.saveImage(files.photo[0].path, 'public/Image/', multiple);
console.log(saveImage);
<video src="video/<%= file.filename %>" controls alt="">
//Try adding the controls command in the video tag. It helps the video run.

looking to upload multiple images with express-fileupload

looking to upload multiple images i am able to do it individually as in code but now i want all gallery images to be sent in a single input and support multiple uploads without restricting numbers here is my code.
router.post('/add-product', isAdmin, function (req, res, next) {
console.log(req.files);
errorMsg = req.flash('error')[0];
successMsg = req.flash('success')[0];
var imageFile, imageFile1, imageFile2, imageFile3;
if (!req.files) {
res.send('No files were uploaded.');
return;
}
imageFile = req.files.imageFile;
imageFile1 = req.files.imageFile1;
imageFile2 = req.files.imageFile2;
imageFile3 = req.files.imageFile3;
imageFile.mv('public/images/' + req.user._id + req.body.code + req.body.name + '.png', function (err) {
if (err) {
res.status(500).send(err);
}
});
imageFile1.mv('public/images/' + req.user._id + req.body.code + req.body.name + 'g1' + '.png', function (err) {
if (err) {
res.status(500).send(err);
}
});
imageFile2.mv('public/images/' + req.user._id + req.body.code + req.body.name + 'g2' + '.png', function (err) {
if (err) {
res.status(500).send(err);
}
});
imageFile3.mv('public/images/' + req.user._id + req.body.code + req.body.name + 'g3' + '.png', function (err) {
if (err) {
res.status(500).send(err);
}
});
product = new Product({
name: req.body.name,
code: req.body.code,
Wifi: req.body.Wifi,
campfire: req.body.campfire,
Pool: req.body.Pool,
parking: req.body.parking,
title: req.body.title,
Duration: req.body.Duration,
Product_Group: req.body.Product_Group,
price: parseFloat((req.body.price * 100).toFixed(2)),
description: req.body.description,
shippable: req.body.shippable,
taxable: req.body.taxable,
category: req.body.category,
Longitude: req.body.Longitude,
Latitude: req.body.Latitude,
imagePath: '/images/' + req.user._id + req.body.code + req.body.name + '.png',
imagePathg1: '/images/' + req.user._id + req.body.code + req.body.name + 'g1' + '.png',
imagePathg2: '/images/' + req.user._id + req.body.code + req.body.name + 'g2' + '.png',
imagePathg3: '/images/' + req.user._id + req.body.code + req.body.name + 'g3' + '.png',
});
console.log(product);
product.save(function (err) {
if (err) {
req.flash('error', 'Error: ' + err.message);
return res.redirect('/admin/products');
}
//console.log("product: " + product);
return res.redirect('/admin/products');
});
});
the front part is as in the below code html part of the same with different inputs for different images but now looking to make multiple inputs for the same the node module supporting the function is express-fileupload
<div class="form-group">
<ul class="list-group">
<li class="list-group-item">
<label for='imageFile'>Display Image</label>
<input type='file' name='imageFile' class='form-control'>
</li>
</ul>
</div>
<div class="form-group">
<ul class="list-group">
<li class="list-group-item">
<label for='imageFile1'>Gallery1</label>
<input type='file' name='imageFile1' class='form-control'>
</li>
</ul>
</div>
<div class="form-group">
<ul class="list-group">
<li class="list-group-item">
<label for='imageFile2'>Gallery2</label>
<input type='file' name='imageFile2' class='form-control'>
</li>
</ul>
</div>
<div class="form-group">
<ul class="list-group">
<li class="list-group-item">
<label for='imageFile3'>Gallery3</label>
<input type='file' name='imageFile3' class='form-control'>
</li>
</ul>
</div>
You can do something like this
if(req.files){
const file = req.files.filename;
for(let i = 0 ; i < file.length; i++){
file[i].mv('./upload/'+file[i].name, function (err){
if(err){
res.send(err);
}
})
}
res.send('files uploaded);
}
Make sure to change the upload directory to ur directory
Using express-fileupload, I uploaded multiple and single images
if (!req.files) {
next()
}
else {
//for uploading mutiple images
var uploadedFiles = []
// images is a field name
uploadedData = req.files.images
if(uploadedData.length > 1){
for (let i = 0; i < uploadedData.length; i++) {
const uploadPath = path.join(__dirname, '..', '/uploads/',
uploadedData[i].name)
const fileName = path.join(__dirname, '..', '/uploads/',
uploadedData[i].name)
uploadedFiles.push(fileName)
res.filepath = uploadedFiles
uploadedData[i].mv(uploadPath, function (err) {
if (err) {
res.send(err);
}
})
}
}
else{
// for single image
const uploadPath = path.join(__dirname, '..', '/uploads/', uploadedData.name)
const fileName = path.join(__dirname, '..', '/uploads/', uploadedData.name)
uploadedFiles.push(fileName)
res.filepath = uploadedFiles
uploadedData.mv(uploadPath, function (err) {
if (err) {
res.send(err);
}
})
}
next()
}
}
In this code I am trying to save a file in the ./uploads folder and entering the details into a database as i move each file, also i am changing the file name as they get moved to the uploads folder with a unique name. I used a library called uniqueFilename for this you can omit the uniqueFilename and database operations as per your need. Also var ext is used to store the extension of that file and used later to add in the database..
You can also call savemulti to save a single file.
const savemulti = async (file)=>{
var filename = file.name
var re = /(?:\.([^.]+))?$/;
var ext = re.exec(filename)[1];
var nm = uniqueFilename('')
file.mv('./uploads/'+nm+'.'+ext,(err)=>{
if(err){
throw err
}else{
var sql3 = "insert into your_db_name (name1,name2,filetitle,mime_type,file_size,upload_date) values (?)";
var date = new Date();
var values = [filename,nm+'.'+ext,filename,file.mimetype,file.size,date]
con.query(sql3,[values],(err,result)=>{
if(err){throw err}
console.log("Inserted")
})
}
})
return Promise
}
const savefiles = async (filesarray)=>{
for(const file of filesarray)
{
await savemulti(file)
}
return Promise.resolve(1)
}
app.post('/testfileupload',async (req,res)=>{
if(req.files)
{
console.log(req.files)
const file = req.files.Upload
try{
if(Array.isArray(file))
{
await savefiles(file).then(()=>{
res.status(200).send("File uploaded")
})
}
}catch(err){
return res.status(404).send('an error occured')
}
}else{
res.status(404).send('no file attached');
}
})
Front end:
<form method="POST" action=".../add-product" enctype="multipart/form-data">
<input multiple type="file" name="images" />
<input type="submit" />
</form>
Back end:
app.post('/add-product', async (req, res) => {
if (!req.files) {
return res.send({
success: false,
message: 'No image uploaded!'
});
}
const file = req.files.images;
const data = [];
function move(image) {
try { image.mv('public/images/' + image.name); }
catch (e) {
return res.send({
success: false,
message: 'upload error'
});
}
data.push({
name: image.name,
mimeType: image.mimetype,
size: image.size
});
}
Array.isArray(file) ? file.forEach((file) => move(file)) : move(file);
return res.send({ success: true, message: 'uploaded successfully', data });
});

EJS cannot read property of undefined, how can I fix this?

My site has broken between now and last night, even though I didn't change anything. I'm making a site which grabs weather data. It's based directly on a medium article here: https://codeburst.io/build-a-weather-website-in-30-minutes-with-node-js-express-openweather-a317f904897b
Here's the server js content...
app.post('/', function (req, res) {
let city = req.body.city;
let country = req.body.country;
let url = `http://api.openweathermap.org/data/2.5/weather?q=${city}${
country.length > 0 ? "," + country : ""
}&units=imperial&appid=${api}`
request(url, function(err, response, body){
if (err) {
res.render('index',
{weather: null, error: "Please Enter Valid Location"});
}
else {
let weather = JSON.parse(body)
if (weather.main == undefined) {
res.render('index',
{weather: null, error: "Please Enter Valid Location"});
}
else {
let content = {
temp: weather.main.temp,
city: weather.name,
condition: weather.weather[0].description,
icon: "svgs/" + weather.weather[0].icon + ".svg"
}
res.render('index', {weather: content, error: null});
}
}
})
});
And here's the corresponding EJS templates...
<% if (locals.weather !== null){ %>
<p><%= locals.weather.city %></p>
<p><%= locals.weather.condition %></p>
<% } %>
<% if(error !== null){ %>
<p><%= error %></p>
<% } %>
It worked last night, but now it's saying "Cannot read property 'city' of undefined".

Resources