Incorrect syntax near '?' - node.js

I have 2 drop down menus that are being populated using a query in SQL Server. Based on the selected items, I am loading a different ejs template. I have done this using the help of AJAX. However, I want to be able to load the data according to the selected criteria. For instance, if DD1 is selected as Andrew and DD2 as Date the table should load 7 columns based on those conditions.
AKA
SELECT * FROM exTable x WHERE x.Name = Andrew and x.Date = '4/22/2019
router.js
router.get('/', async (req, res) => {
try {
var name = await conn.query("SELECT DISTINCT pr.Name FROM WFS.PRTABLE pr WHERE pr.Functional_Group = 'Test'");
var dates = await conn.query('SELECT r.Date FROM WFS.Dates r');
res.render('index', {name : name , dates: dates});
} catch (err) {
res.status(500)
res.send(err.message)
}
});
router.post('/selection', async (req, res) =>{
try {
var name = await conn.query("SELECT DISTINCT pr.Name FROM WFS.PRTABLE pr WHERE pr.Group = 'Test'");
var dates = await conn.query('SELECT r.Date FROM WFS.Dates r');
var dateID = req.body.Dates;
var nameID = req.body.Names;
var tables = await conn.query("SELECT * FROM WFS.Views v WHERE v.Name = ? AND v.Date = ?", [ nameID , dateID ], function(err){
if(err) throw err;
res.render('selection', {tables: tables, name : name , dates: dates});
});
}
catch (err) {
res.status(500)
res.send(err.message)
}
});
index.ejs
<script>
$(document).ready(function(){
$('#date').on('change', function(event) {
var dates = $('#selections option:selected').val();
});
$('#name').on('change', function(event) {
var manVal = $('#selection option:selected').val();
alert(manVal);
});
$('#submitData').on('submit', function(e){
e.preventDefault();
$.ajax({
type: "POST",
url: "/selection",
data: {dates : dates , manVal: manVal},
success: function() {
alert('success');
}
});
});
});
</script>
<form action="/selection" method="POST">
<select class="DateDD" id="date" name="Dates">
<% for(var n=0; n < dates.recordset.length; n++) { %>
<option><%= dates.recordset[n].Date%></option>
<% } %>
</select>
<select class="NameDD" id="name" name="Names">
<% for(var n=0; n < name.recordset.length; n++) { %>
<option><%= name.recordset[n].Name%></option>
<% } %>
</select>
<input type="submit" name="Submit" id="submitData" class="btn btn-primary" value="View Report" />
</form>
selection.ejs
CONTAINS THE SAME THING AS INDEX.EJS (besides the <script> tag) AND ...
<table class="table table-bordered table-condensed table-striped">
<% for(var n=0; n < tables.recordset.length; n++) { %>
<tr>
<td><%=tables.recordset[n].Name%></td>
<td><%=tables.recordset[n].Date%></td>
....
....
....
....
</tr>
<% } %>
</table>
This is the error I receive: Incorrect syntax near '?' after I hit the submit button.

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...

Catch the response in AngularJS function from a res.send csv file

I need to catch the response (I mean checking when the response from a NodeJS function return to the client, not like an error) from a NodeJS function.
When the button is clicked, a function with a form starts and NodeJS, after a query, returns a csv file. The problem is that the query is complex and it requires 1+ minutes to complete.
I need to make a loading spinner start when the button is clicked, and it should stop when the CSV is returning from the function. Any clue on how can I do that? Thanks in advance.
HTML form
<form name="csvForm" ng-submit="download(csvForm.$valid)">
<div class="panel-body">
<div class="row">
<div class="form-group col-sm-4">
<label class="control-label">Concessionaria<span ng-if="userProfileID != 1">*</span></label>
<select class="form-control" ng-model="Dealer"
ng-options="dealer.ID as dealer.Name for dealer in dealers "
ng-required="userProfileID != 1">
<option value=""></option>
</select>
</div>
<div class="form-group col-sm-4">
<label class="control-label">Anno*</label>
<select class="form-control" ng-model="Year"
ng-options="y as y for y in syears" required>
<option value=""></option>
</select>
</div>
</div>
</div>
<div class="form-group col-sm-4 col-sm-offset-4" style="margin-top:20px">
<button name="submitBtn" class="btn btn-lg btn-primary btn-block" type="submit" >Scarica CSV</button>
</div>
</form>
Angular
$scope.download = function () {
var form = document.createElement('form');
form.action = apihost + "/queryReport/avanzEvaluation";
form.method = 'POST';
form.target = '_blank';
form.style.display = 'none';
var jsonData = {
dealer: $scope.Dealer,
year: $scope.Year
};
var inputJson = document.createElement('input');
inputJson.type = 'text';
inputJson.name = 'data';
inputJson.value = JSON.stringify(jsonData);
var submit = document.createElement('input');
submit.type = 'submit';
submit.id = 'submitProject';
form.appendChild(inputJson);
form.appendChild(submit);
document.body.appendChild(form);
//Send form.
form.submit();
document.body.removeChild(form);
};
NodeJS
router.post('/avanzEvaluation', function (req, res) {
return new Promise(function(resolve,reject) {
//Not the real query, just an example
var sql = "SELECT * FROM Table ";
return models.sequelize.query(sql, {replacements: replacements, type: models.sequelize.QueryTypes.SELECT })
.then(function (results) {
const Json2csvParser = require('json2csv').Parser;
//Not real fields, just examples
const fields = ["Field1", "Field2", "Field3", "Field4",];
const opts = { fields };
try {
const parser = new Json2csvParser(opts);
const csv = parser.parse(results);
var filename = ("avanzValutazioni.csv");
res.header("Content-Disposition","attachment;filename=" + filename);
res.setHeader('content-type', 'text/csv');
res.send(iconv.encode(csv, 'iso-8859-1'));
}
catch (err) {
console.error(err);
}
})
.catch(function (err) {
console.log(err);
});
})
});
To start and stop a spinner using the http service, use the .finally method of the $http promise:
$scope.spinner = true;
var promise = $http.post(url, data);
promise.finally(function() {
$scope.spinner = false;
});
<div ng-if="spinner">
<!-- Put spinner here -->
</div>
For more information, see
AngularJS $q Service API Reference - The Promise API
I figured out how to do it, thanks to #georgeawg too!
I resolved by returning a json with the filename and complete csv (csv format) without downloading it from the NodeJS function to the front end. Then I manipulate the result in front end to trigger the csv download with the result.
AngularJS
$scope.download = function () {
//Spinner
usSpinnerService.spin('spinner-1');
//Custom data from the Form, sent as a JSON
var jsonData = {
year: $scope.Year
};
if($scope.Dealer) {
jsonData.dealer = $scope.Dealer;
}
//I've could have done this with a options variable, but i prefer it inline
$http.post(apihost + "/queryReport/avanzEvaluation_TEST", {data: jsonData}, {headers: {'Content-Type': 'application/json'}})
.success(function (result) {
//If the query returns a non-empty csv
if(result.csv.length > 0) {
usSpinnerService.stop('spinner-1');
//This if-else is used to make it work on Edge too
if (window.navigator.msSaveOrOpenBlob) {
var blob = new Blob([result.csv]);
window.navigator.msSaveOrOpenBlob(blob, result.filename);
}
else {
var a = document.createElement("a");
a.href = "data:attachment/csv," + encodeURIComponent(result.csv);
a.target = "_blank";
a.download = result.filename;
document.body.appendChild(a);
a.click();
}
}
//Otherwise I show an error with the module Notification
else {
Notification.error("Non รจ stato possibile eseguire il download del file CSV.");
}
});
}
NodeJS
router.post('/avanzEvaluation_TEST', function (req, res) {
return new Promise(function(resolve,reject) {
//Not the real query, just an example
var sql = "SELECT * FROM Table ";
return models.sequelize.query(sql, {replacements: replacements, type: models.sequelize.QueryTypes.SELECT })
.then(function (results) {
const Json2csvParser = require('json2csv').Parser;
//Not real fields, just examples
const fields = ["Field1", "Field2", "Field3", "Field4",];
const opts = { fields };
try {
const parser = new Json2csvParser(opts);
const csv = parser.parse(results);
var filename = ("avanzValutazioni.csv");
res.json({filename: filename, csv: csv});
}
catch (err) {
console.error(err);
}
})
.catch(function (err) {
console.log(err);
});
})
});

I want to create a Search method that autodisplay some results

I'm creating a function that is looking for users in database.
I've done the server-side code, but I don't know how to display the results in the html code. I know that I have to write some JavaScript code but I don't know how
I found something on Google, but it doesn't work.
This is my route.
router.get('/search', isAuth, feedController.getSearch);
This is my controller.
exports.getSearch = (req,res,next) => {
const search = req.query.searchField;
User.find({
firstname:{
$regex: new RegExp(search)
},
}, {
_id:0,
__v:0
}, function (err,data) {
res.json(data);
}
).limit(10);
}
This is my HTML
<li>
<div class="search-box">
<form action="/search" method="GET" class="form-inline my-0 my-lg-0">
<input type="text" aria-label="Search" class="form-control mr-sm-0" onkeyup="showResults(this.value)" placeholder="Mirror-Mirror Search">
<span class="hightlight"></span>
<span class="bar"></span>
</input>
<button type="submit" class="search-btn"><i class="fas fa-search"></i></button>
</form>
</div>
<div style="position: relative; width:100%; top:-1px;">
<div class="border" id="search-results"></div>
</div>
</li>
And this is what I found on Google
var showResults = debounce(function(arg) {
var value = arg.trim();
if(value == "" || value.length <=0)
{
$("#search-results").fadeOut();
return;
}
else {
$("#search-results").fadeIn();
}
var jgxh = $.get('/controllers/feed/getSearch?searchField=' + value, function(data) {
$("#search-results").html("");
})
.done(function(data){
if(data.length === 0) {
$("#search-results").append('<p class="lead text-center mt-2">No results</p>');
} else {
data.forEach(x => {
$("#search-results").append('<a href="#> <p class="m-2 lead>' +x.firstname+' '+x.lastname + '</p></a>')
});
}
})
.fail(function(err){
console.log(err);
})
},200)
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this;
args = arguments;
var later = function () {
timeout = null;
if(!immediate) func.apply(context,args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if(callNow) func.apply(context,args);
};
};
I expected to autodisplay the results, but It doesn't work. I want to search in my database either for 'firstname' or 'lastname', I hope you can help me, thank you!

Add an object to a sub document list of object Node.js Express

I have been trying to append a DOM object to a list of object into a Sub document of my Mongo database. However, so far no avail. Im retrieving the data from an html form in which i grouped the data in objects. I first tried to use a forEach loop, but i kept getting an message saying that the $addToSet is empty, eventhough when i log the Objects im retrieving from the DOM seems to not be empty. I applied this is same approach, in a put request from a previous route whilst then i had no problem updating the database. This is my first application, im still a noob, so you help would be very much appreciated.
// my database Schema
// schema for images
var images = new Schema(
{
title: String,
description: String,
link: String
}
);
// shema lower for the tes dictionary
var days = new Schema({
day: Number,
route: String,
distance: Number,
description: String,
imageamount: Number,
images: Array(images),
})
// schema upper for the test dictionary
var tourSchema = new Schema({
date: String,
thumbnail: String,
categories: Array,
title: String,
locations: Array,
duration: Number,
generalDescription: String,
dayInfo: Array(days),
});
var Tour = mongoose.model("Tour", tourSchema);
// this is the code Im using to update the db
app.put("/tours/:id/dayinfo/images", (req, res) => {
Tour.findById(req.params.id, (err, tour) => {
if (err) {
console.log("error");
} else {
for( var i = 0; i < tour.dayInfo.length; i++) {
for (var j = 1; j <= tour.dayInfo[i].imageamount; j++){
Tour.updateOne({_id: tour.dayInfo[i]._id}, {$addToSet: { images: req.body["images" + String(Number(i+1)) + String(j)] } },{upsert: true}, (err, updatedImages) => {
if (err) {
console.log(err);
} else {
console.log(updatedImages);
}
})
}
console.log("updated imagess for images ");
};
res.redirect("/");
}
})
});
<form class="some-form" action="/tours/<%= tour._id %>/dayinfo/images?_method=PUT" method="POST">
<% tour.dayInfo.forEach ( (day) => { %>
<header>
<h3>Images of <b>Day <%= day.day %><b></h3>
</header>
<hr>
<% for (var i = 1; i <= day.imageamount; i++ ) { %>
<!-- tour info -->
<div class="row">
<div class="col-md-6">
<input type="text" name="images<%= day.day %><%= i %>[title]" value="" placeholder="Short title of image" class="form-control">
</div>
<div class="col-md-6">
<input type="text" name="images<%= day.day %><%= i %>[description]" value="" placeholder="Short description of image" class="form-control">
</div>
</div>
<br>
<input type="text" name="images<%= day.day %><%= i %>[link]" value="" placeholder="link of image" class="form-control">
<br>
<% } %>
<% }); %>
<input type="submit" name="" value="SAVE" class="btn btn-success btn-block">
</form>
// this code seems to work, yet when applying the same approach for a deeper laying doc, it does not work i get a message saying that '\'addToSet'\' is empty.
/ update({_id: ObjectId("5bf404f0fd415e077e849694")}, {$addToSet: {dayInfo: {day: 8} }}, {upsert: true} )
app.put("/tours/:id/dayinfo", (req, res) => {
Tour.findById(req.params.id, (err, tour) => {
if (err) {
console.log(err)
} else {
for (var i = 1; i <= tour.duration; i++){
Tour.update({_id: req.params.id}, {$addToSet: { dayInfo: req.body["dayInfo" + String(i)] } }, {upsert: true}, (err, updatedDayInfo) => {
if (err) {
console.log(err);
} else {
console.log(req.body["dayInfo" + String(i)]);
}
})
console.log("successfully updated day " + i );
}
}
})
res.redirect("/tours/" + req.params.id + "/dayinfo/images" );
});

extract data from html table to nodejs post request

I fill html table with data from database (user's emails and their roles in my system (admins and users)).
router.get('/adminOffice', function(req, res){
database.connection.query("select email, role from users", function(err, rows, fields){
if(err) console.log(err);
res.render('adminOffice', {rows: rows});
});
});
With the help of ejs it looks next (adminOffice.ejs):
<form method="post" action="saveRoles">
<table name="table" id="table"><tr>
<th>Email</th><th>Role</th>
</tr>
<% for (var i = 1; i < rows.length; i++) { %>
<tr class="tableclass">
<td><%= rows[i].email %></td>
<td> <select class="select">
<% if (rows[i].role == 'admin') { %>
<option selected value="admin">admin</option>
<option value='user'>user</option>
<% } else { %>
<option selected value="user">user</option>
<option value="admin">admin</option>
<% } %>
</select>
</tr>
<% } %>
</table>
<input type="submit" name="submit" value="submit" />
</form>
If I want to change some user's role I need to extract the data from table to JSON format for example in post request, how can I do this?
I tried to use request and cheerio
router.post('/saveRoles', function(req, res, next){
request.get('http://127.0.0.1:3000/adminOffice', function(err,
response, body, callback){
var $ = cheerio.load(body);
var result = $(".tableclass").map((i, element) => ({
email: $(element).find('td:nth-of-type(1)').text(),
role: $(element).find('.select option:selected').text()
})).get();
console.log(result[0].role);
database.connection.query("select email, role from users", function(err, rows, fields){
if(err) console.log(err);
for(var i = 1; i < rows.length; i++){
if(rows[i].role != result[i-1].role){
database.connection.query("update users set role = ? where email = ?", rows[i].role, rows[i].email, function(err, res){
if(err) console.log(err);
console.log("success");
});
} else {
console.log("not success");
}
}
});
});
res.redirect('/adminOffice');
});
but they works with new /adminOffice page and with initial values there.
For example there're 2 users in my table: {email: user1#user, role: user}, {email: user2#user, role: user}, I change role of 1st user to admin and press sumbit, request loads new adminOffice page where 1st user again has role user so post logs double not success and DB never changed.
Maybe I should use AJAX or smth else (new to NodeJS and JS)
Changed html code:
<form method="post" action="/saveRoles">
<% for (var i = 1; i < rows.length; i++) { %>
<div class="form-group">
<label for="changingRole"> <%= rows[i].email %></label>
<select name="role">
<% if (rows[i].role == 'admin') { %>
<option selected value='admin'>admin</option>
<option value="user">user</option>
<% } else { %>
<option selected value="user">user</option>
<option value="admin">admin</option>
<% } %>
</select>
</div>
<% } %>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
so I can easy now extract roles and work with them further
router.post('/saveRoles', urlencodedParser, function(req, res, next){
var roles = req.body;
database.connection.query("select email, role from users", function(err, rows, fields){
if(err) console.log(err);
for(var i = 1; i < rows.length; i++){
console.log(rows[i].role);
console.log(roles.role[i-1]);
if(rows[i].role != roles.role[i-1]){
database.connection.query("update users set role = ? where email = ?", [roles.role[i-1], rows[i].email],
function(err, res){
if(err) console.log(err);
console.log("success");
});
} else {
console.log("not changed");
}
}
});
res.redirect('/adminOffice');
});

Resources