Select option dropdown with Node.js, MySQL and EJS - javascript

I would like to make a drop-down list with the data from my MySQL database, in this case I am trying to make when filling out my "create budgets" form to extract the names from the "customer" table and place them in a select option, I'm using EJS. However, I also have problems when passing EJS data since it gives me an error in the browser (Data not defined)
This is my controller to save data:
controller.save = function(req, res, next) {
const data = req.body;
req.getConnection((err, conn) => {
conn.query('SELECT nombre FROM clientes', (err, row) =>{
res.render('presupuestos_create', {
datos: row
})
});
conn.query('INSERT INTO presupuestos set ?', [data], (err, row) => {
res.redirect('/presupuestos');
});
});
};
And this is mi EJS:
<form action="/presupuestos/add" method="POST">
<div class="mb-3">
<label for="cliente" class="form-label">Cliente</label>
<select class="form-select" id="cliente" name="cliente" tabindex="1" required>
<option>----</option>
<%for(var i=0; i < datos.length; i++){%>
<option value="<%= datos[i] %>"><%= datos[i] %></option>
<%}%>
</select>
</div>

to populate from db > ejs
<select class="form-select" id="cliente" name="cliente" value="<%= datos%>" tabindex="1" required>
<% for(var i=0; i < datos.length; i++) { %>
<option
<%= datos[i].datos %>
</option>
<%}%>

Related

how can I activate the edit button? mongodb

I got this error
CastError: Cast to ObjectId failed for value "details5f9c3b069dc8723528c64cc8" at path "_id" for model "Book"
the edit and delete button are not activated.
Help me to figure it out please. this is /routes/books.js
and what else do I upload here?
// GET edit an existing Book
router.get('/:id', (req, res, next) => {
let id = req.params.id;
book.findById(id, (err, bookToEdit) => {
if(err) {
console.log(err);
//res.end(err);
} else {
//show the edit view
res.render('books/details', {title: 'Edit Book', books: bookToEdit})
}
});
});
// POST and update the document
router.post('/:id', (req, res, next) => {
let id = req.params.id
let updatedBook = book({
_id: id,
title: req.body.title,
description: req.body.description,
price: req.body.price,
author: req.body.author,
genre: req.body.genre
});
book.updateOne({_id: id}, updatedBook, (err) => {
if(err) {
console.log(err);
res.end(err);
} else {
// refresh
res.redirect('/books');
}
});
});
// GET - process the delete by user id
router.get('/delete/:id', (req, res, next) => {
let id = req.params.id;
book.remove({_id: id}, (err) => {
if(err) {
console.log(err);
res.end(err);
} else {
// refresh
res.redirect('/books');
}
});
});
This is /books/details.ejs
<div class="container">
<div class="row">
<form class="form" method="post">
<div class="form-group">
<label for="TitleTextField">Title</label>
<input type="text" class="form-control" id="TitleTextField"
placeholder="Book Title" name="title" value="<%= books.Title %>" required>
</div>
<div class="form-group">
<label for="AuthorTextField">Author</label>
<input type="text" class="form-control" id="AuthorTextField"
placeholder="Book Author" name="author" value="<%= books.Author %>" required>
</div>
<div class="form-group">
<label for="PriceTextField">Price</label>
<input type="text" class="form-control" id="PriceTextField"
placeholder="Book Price" name="price" value="<%= books.Price %>" required>
</div>
</div>
</div>
and this is /books/indexejs
<% include ../partials/header.ejs %>
<!-- MAIN CONTENT -->
<div class="container">
<div class="row">
<!--Add-->
<i class="fa fa-plus"></i> Add a book
<br>
<br>
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Title</th>
<th class="text-center">Author</th>
<th class ="col-4">Price</th>
<th class="text-center">EDIT</th>
<th class="text-center">DELETE</th>
</tr>
</thead>
<tbody>
<% for (let count = 0; count < books.length; count++) { %>
<tr>
<td><%= books[count].Title %></td>
<td class="text-center"><%= books[count].Author %></td>
<td class="text-center">$<%= books[count].Price %></td>
<!--EDIT-->
</td>
<td class="text-center">
<a href="/books/edit<%= books[count].id %>" class="btn btn-primary btn-sm">
<i class="fas fa-pencil-alt"></i> Edit</a>
</td>
<!--DELETE-->
<td class="text-center">
<a href="/books/delete<%= books[count].id %>" class="btn btn-danger btn-sm">
<i class="fas fa-trash-alt"></i> Delete</a></td>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
</div>
</div>
<% include ../partials/footer.ejs %>
this is /models/books.js
let mongoose = require('mongoose');
let Book = mongoose.Schema({
Title: String,
Description: String,
Price: Number,
Author: String,
Genre: String
},
{
collection: "books"
});
module.exports = mongoose.model('Book', Book);
hope these are helpful to fix the problems
You have an error that said that book.find and book.delete need an ObjectId as parameter. And details5f9c3b069dc8723528c64cc8 is not a valid ObjectId for Mongo.
Just read the error message !
Edition
Maybe you face this problem because you made a little mistake with resources, using same http POST to create and edit, giving the :id in path in both case.
If you have a POST / (no id in path) method to create books, letting mongodb generate ids, and have a PATCH (or PUT) /:id method to update those books, you probably will not have this kind of error anymore.
It will maybe sounds like stupid duplication but as your app will grow, you certainly will need to add some specific security rules.
Also, if I remember mongoose correctly, you're not supposed update the _id in second parameter for updateOne.
//no _id present in updatedBook
book.updateOne({_id: id}, updatedBook, (err) => { };
The default key of a document in MongoDB is _id who set an ObjectId in it.
ObjectId is a unique key who contained from some meaningful base on date and time (you can convert objectId to date).
You can read more about it here.
And your problem, it's really easy. You concat your ObjectId with details as you can see in the error.
details5f9c3b069dc8723528c64cc8 => 5f9c3b069dc8723528c64cc8

Express-validator throwing error with valid fields

I'm relatively new to node and express, and have come across a problem I can't seem to solve.
So I came across with the problem trying to validate a create product form, that when I introduce correct values into the fields express-validator throws error.
This is my routes code:
router.post('/create', [
check('name').isLength({ min: 5 }).withMessage("Invalid Value"),
check('description').isLength({ min: 20 }).withMessage("Invalid Value")
] , upload.any() , productosController.guardarCreado);
This is my productosController code:
guardarCreado: (req, res, next) => {
let errors = validationResult(req);
if(errors.isEmpty()){
db.Product.create({
name: req.body.nombre,
description: req.body.descripcion,
size: req.body.talle,
price: req.body.precio,
category_id: 2,
img_url: req.files[0].filename
})
res.redirect('/productos');
}else{
db.Category.findAll()
.then(function(categorias){
return res.render('crearProductos', { categorias: categorias, errors: errors.errors });
})
}
}
And my form code is from Bootstrap and the names of the form fields are the same as the names on the 'check' from my routes code:
<div class="col-md-3 mb-3">
<label for="validationDefault03">Nombre del Producto</label>
<input name="name" id="nombre" type="text" class="form-control" placeholder="Ej: Remera River Plate" >
</div>
<div class="col-12">
<label for="description" class="form-label">DescipciĆ³n:</label><br>
<textarea name="description" id="description" class="form-input"></textarea>
</div>
Error display on the the form via EJS:
<% if (typeof errors != 'undefined') { %>
<p style= "color: red">ERROR</p>
</div>
<ul>
<% for(let i = 0; i < errors.length; i++) { %>
<li>
<%= errors[i].msg %>
</li>
<% } %>
</ul>
<% } %>

Inside bootstrap dual list box, on selection of an option I want to separate only one value from all other values inside of value attribute

I have a bootstrap list box containing a number of options. Each option is a medical test and has a value attribute. This value attribute has many values init separated by comma e.g it has Test Name, Test Code and Test Rate, etc. In onchange function of the dual list box, I want to get only Test Rate from all the other values present inside the value attribute.
Note: I cannot put the only Test Rate inside value attribute because I need other values also.
Html Code of my dual list box
<div class="form-group row">
<label class="col-sm-2 text-right col-form-label no-padding-top" for="Test">Test </label>
<div class="col-sm-10">
<select class="form-control" multiple="multiple" size="4" name="test_id" onchange="add_total()" id="duallist">
<% tests.forEach(test => { %>
<option value="<%- test.ID %> , <%- test.Code %> , <%- test.Name %> , <%- test.Type %> , <%- test.TemplateID%> , <%- test.Rate %>"><b><%- test.Code %></b> <%- test.Name %></option>
<% }) %>
</select>
</div>
</div>
Onchange function of the dual list box is bellow. Here I want to get only Test Rate.
function add_total() {
var sum = 0.0;
$('#duallist option:selected').each(function() {
//Want to get only Rate here not the whole value attribute how can I do that
var total = parseInt($(this).attr('value'));
sum = (sum + total);
document.getElementById("subtotal").value = sum;
});
}
In your case, you can separate specific data(Test Rate) from all other data of your value attribute by placing your specific data(Test Rate) inside value2 attribute while all other data remains inside value attribute as
<div class="form-group row">
<label class="col-sm-2 text-right col-form-label no-padding-top" for="Test">Test </label>
<div class="col-sm-10">
<select class="form-control" multiple="multiple" size="4" name="test_id" onchange="add_total()" id="duallist">
<% tests.forEach(test => { %>
<option value="<%- test.ID %> , <%- test.Code %> , <%- test.Name %> , <%- test.Type %> , <%- test.TemplateID %>" value2="<%- test.Rate %>"><b><%- test.Code %></b> <%- test.Name %></option>
<% }) %>
</select>
</div>
</div>
Now inside onchange function for the dual list box, you can access you specific data(Test Rate) easily as
function add_total() {
var sum = 0.0;
$('#duallist option:selected').each(function() {
var total = parseInt($(this).attr('value2'));
sum = (sum + total);
document.getElementById("subtotal").value = sum;
});
}
All the other data is still available to you inside the value attribute as you needed so

Cannot get data from form with query selector

I can't get the data from the input of the form, it seems like the only function of the submit button is to refresh the page.
const Form = document.querySelector('.broadcast-form')
Form.addEventListener('submit', (e) => {
e.preventDefault()
const cliente = Form.querySelector('#clienti').options[clienti.selectedIndex].text
console.log(cliente)
})
<form class="container broadcast-form">
<select multiple class="form-control" id="clienti" style="height: 150px" onchange="selectCustomer()">
<!--
<% for(var i=0; i<clienti.length; i++) {%>
<option><%= clienti[i]["Cliente"] + " CL: " + codiceLisa[i]["Codice_Lisa"] %></option>
<% } %>
-->
<option>Foo CL: ABC</option>
<option>Bar CL: DEF</option>
<option>Baz CL: GHI</option>
</select>
<input type="submit" class="btn btn-primary btn-lg" value="Genera XML" />
</form>
When you look at the JavaScript console of your browser, you'll see that it complains about not being able to read a property of undefined. This is caused by clienti not being defined in your JavaScript code, in the clienti.selectedIndex part. Defining it seems to resolve your issue.
As a bonus: you may want to consider using selectedOptions to find all selected options in the select, given that it has the multiple attribute. The selectedIndex will only give you the first one.
function selectCustomer() {
/* defined only to prevent errors when changing the value of the select */
}
const form = document.querySelector('.broadcast-form');
form.addEventListener('submit', (e) => {
e.preventDefault()
let clienti = form.querySelector('#clienti'),
cliente = (clienti.selectedIndex < 0 ? null : clienti.options[clienti.selectedIndex].text);
console.log(cliente);
// bonus:
for (let clienteEl of clienti.selectedOptions) {
console.log(`bonus: ${clienteEl.text}`);
}
})
<form class="container broadcast-form">
<select multiple class="form-control" id="clienti" style="height: 150px" onchange="selectCustomer()">
<!--
<% for(var i=0; i<clienti.length; i++) {%>
<option><%= clienti[i]["Cliente"] + " CL: " + codiceLisa[i]["Codice_Lisa"] %></option>
<% } %>
-->
<option>Foo CL: ABC</option>
<option>Bar CL: DEF</option>
<option>Baz CL: GHI</option>
</select>
<input type="submit" class="btn btn-primary btn-lg" value="Genera XML" />
</form>

ExpressJS Comma Separating Values

I am trying to create a tagging system for my records, and assumed that I would be able to create separate tags by using req.body.tags.trim().split(","); on my post method, but all of the comma separated values I provide are displated as one URL.
Values being written:
Values displayed and hovered over:
POST method:
router.route('/admin/posts/create')
// START POST method
.post(function(req, res) {
console.log("New instance");
var blogpost = new Blogpost(); // create a new instance of a Blogpost model
blogpost.title = req.body.title; // set the blog title
blogpost.featureImage = req.body.featureImage; // set the blog image
blogpost.blogUrl = blogpost.title.toLowerCase().replace(/\s+/g,"-");
blogpost.author = req.body.author; // set the author name
blogpost.tagline = req.body.tagline; // set the tagline
blogpost.content = req.body.content; // set the blog content
blogpost.category = req.body.category; // set the category
blogpost.tags = req.body.tags.trim().split(","); // set the tags
//Save Blog Post
blogpost.save(function(err) {
if (err)
res.send(err);
res.redirect(303, '/'); //NEEDS TO BE CHANGED
});
}) // END POST method
.get(isLoggedIn, function(req, res, blogpost) {
res.render('pages/blogpost-create', {
blogpost : blogpost
});
});
Blogpost-create.ejs:
<form action="/admin/posts/create" method="POST">
Header Image: <input type="file" id="files"/>
<p id="status">Please select a file</p>
<div id="preview"><img src="/images/event-placeholder.png"></div>
<input type="hidden" id="feature-image" name="featureImage" value="/images/event-placeholder.png" />
Title: <input type="text" name="title" required></input><br>
Author:
<select name="author">
<option value="Author">Blog Author</option>
</select><br>
Category:
<select name="category">
<option value="Test 1">Test 1</option>
<option value="Test 2">Test 2</option>
<option value="Test 3">Test 3</option>
<option value="Test 4">Test 4</option>
</select><br>
Tagline: <input type="text" maxlength="155" name="tagline" required><br>
Content:<br>
<textarea name="content" id="blog-editor" rows="10" cols="80">
</textarea>
<br>
Tags: <input type="text" name="tags" required>
<br>
<input type="submit" value="Submit">
Blogpost.ejs (Where values are displayed):
<header>
<% include ../partials/header %>
</header>
<div class="container">
<div class="col-md-12">
<div id="blog-content">
<h1><%= blogpost.title %></h1>
<img src="<%= blogpost.featureImage %>" class="img-responsive" id="blogpost-feature-image">
<h3 class="blog-date"><%= blogpost.dateString %></h3>
<h3 class="blog-category"><%= blogpost.category %></h3>
<h3 class="blog-tagline"><i><%= blogpost.tagline %></i></h3>
<p><%- blogpost.content %></p>
<%= blogpost.tags %>
</div>
</div>
</div>
Yeah, you're writing them all into one anchor in your ejs template.
Something like this:
<ul>
<% for(var i=0; i<blog.tags.length; i++) { %>
<li>
<a href='/tags/<%= blog.tags[i] %>'>
<%= blog.tags[i] %>
</a>
</li>
<% } %>
</ul>
I'm assuming that your save logic successfully saves the array as you think, but that's worth checking as well

Categories