Send Data from Span in EJS to Server Nodejs - node.js

Using Nodejs, Express, EJS
I see a lot of 'Send Data from Server to Client' but not from Client to Server AND sending the data from a tag not from a form input.
I would like to send the content of a tag from my ejs page/client to my nodejs/server.
What I'm trying...
page.ejs
<div>
<form action="/brewery" method="GET">
<div class="form-group">
<input type="text" class="form-control"
placeholder="search brewery name"
name="search">
</div>
<input class="button" type="submit" value="Submit">
</form>
</div>
<div>
<ul>
<% searchBreweryList.forEach(function(searchBrewery){ %>
<div>
<li>
Brewery Name: <span><%= searchBrewery.brewery.brewery_name %></span>
Brewery ID: <span name="brewID" id="shareBreweryID"><%= searchBrewery.brewery.brewery_id %></span>
</li>
</div>
<% }) %>
</ul>
</div>
Then on my server side...
server.js
app.get('/brewery', async (req, res) => {
var searchBreweryFound = req.query.search;
var isIndie = req.params.brewID
//console.log(isIndie)
//console.log(searchBreweryFound)
try {
request("https://api.com/v4/search/brewery?access_token=abc123&limit=1&q=" + searchBreweryFound, function (error, response, body)
{
if (error) throw new Error(error);
const searchBrewery = JSON.parse(body);
const searchBreweryList = searchBrewery.response.brewery.items.map(item => item );
res.render('brewery.ejs', {searchBreweryList});
//console.log(searchBreweryList);
});
} catch(e) {
console.log("Something went wrong", e)
}
});
So the above Get call is just an example where I'm trying to take the result in the client side span that looks like <span name="brewID">. Then I'm trying to give that ID number to the server in the var seen as var isIndie = req.params.brewID.
But this does not seem to be a method that allows me to pass content from a span in client to server.
What approach should I be taking? Thanks!

It's not clear what you mean by "sending data from client to server". Standard method of sending data from client to server is using XMLHttpRequest (XHR) inside *.js file(s), but based on your code you want to redirect browser window to URL with some parameters. When browser hit your endpoint, for example /brewery, server will render *.ejs file and respond to browser with HTML code.
Redirecting browser with EJS
Below code is based on code you posted.
<div>
<ul>
<% searchBreweryList.forEach(function(searchBrewery){ %>
<div>
<li>
Brewery Name: <span>
<%= searchBrewery.brewery.brewery_name %>
</span>
Brewery ID: <span name="brewID" id="shareBreweryID">
<%= searchBrewery.brewery.brewery_id %>
</span>
<!-- Here we create link using parameter of brewery (version with param) -->
Go to brewery
<!-- Version with query param -->
Go to brewery
</li>
</div>
<% }) %>
</ul>
</div>
After clicking Go to brewery browser will hit /brewery endpoint with param brewery_id. I also noticed that in posted example var isIndie = req.params.brewID may not work.
Bonus: req.query vs req.params
Both req.query and req.params are used to get some informations from endpoint URL. However req.query and req.params are not the same.
Using req.query
For endpoint: /brewery?id=5&q=test
const id = req.query.id // 5
const q = req.query.q // 'test'
Using req.params
To use req params you must place param name somewhere in url of express endpoint.
app.get('/brewery/:id', async (req, res) => {
var id = req.params.id
})
So to make your example with req.params working:
app.get('/brewery/:brewID', async (req, res) => {
var searchBreweryFound = req.query.search;
var isIndie = req.params.brewID
// Rest of your code
})

Related

Form Select onChange Sends Data/Info to Query on Server

I'm using Nodejs, Express, and EJS.
Here's what works...
I can use an unordered list of hyperlinks and send the info/variable via req.params this way...
db.ejs code
<ul>
<% dbTitle.forEach(function(dbTitle){ %>
<li><%= dbTitle.dbTitle %></li>
<% }) %>
</ul>
server.js code
app.get('/db/:dbTitle', async (req, res) => {
const {dbTitle} = req.params;
console.log(dbTitle);
try {
const tabTitleResult = await session.run(`MATCH (db:Database {Title: $dbTitle})-->(t:Table)-->(tv:TableVersion)
Where NOT (tv)<--(:InformationAsset)
RETURN db.Title as dbTitle, tv.Title as tabTitle Order By db.Title, tv.Title ASC`, {dbTitle});
const tabTitleArr = tabTitleResult.records.map(({_fields}) => {
return {dbTitle:_fields[0],tabTitle:_fields[1]};
});
res.render('table.ejs', { tabTitle: tabTitleArr});
//console.log(tabTitleArr)
} catch(e) {
console.log("Something went wrong", e)
}
});
everything from above displays nicely on this page...
table.ejs code
<table>
<tr>
<th>Database-Title</th>
<th>Table-Title</th>
</tr>
<% tabTitle.forEach(function (tabTitle){ %>
<tr>
<td><%= tabTitle.dbTitle %></td>
<td><%= tabTitle.tabTitle %></td>
<% }) %>
</tr>
</table>
Here's what doesn't work...
Instead of an unordered list of hyperlinks, I would prefer to have a dropdown select, however my code doesn't work when I try to use a form select option method to send the info/variable via req.body...
db.ejs code
<form method="post" action="/db">
<label>Database Name</label><br>
<select name="dbTitle" onchange="this.form.submit();">
<option selected disabled> -- select an option --
<% dbTitle.forEach(function(dbTitle){ %>
<option name="dbTitle" value="<%= dbTitle.dbTitle %>"><%= dbTitle.dbTitle %></option>
<% }) %>
</option>
</select>
</form>
(Note: I am aware of how strange the nested options seem, this is required to force the --select an option-- option to appear first, removing the nesting with only the one option with data does not help.
Also, you'll note that I'm adding name="dbTitle" on more than one element in a desperate attempt to make something work, I believe it should only be on the select element.
Last, I'm also trying to send any info/variable via value="<%= dbTitle.dbTitle %>.)
server.js code
app.post('/db/:dbTitle', async (req, res) => {
const {dbTitle} = req.body;
console.log(dbTitle);
try {
const tabTitleResult = await session.run(`MATCH (db:Database {Title: $dbTitle})-->(t:Table)-->(tv:TableVersion)
Where NOT (tv)<--(:InformationAsset)
RETURN db.Title as dbTitle, tv.Title as tabTitle Order By db.Title, tv.Title ASC`, {dbTitle});
const tabTitleArr = tabTitleResult.records.map(({_fields}) => {
return {dbTitle:_fields[0],tabTitle:_fields[1]};
});
res.render('table.ejs', { tabTitle: tabTitleArr});
//console.log(tabTitleArr)
} catch(e) {
console.log("Something went wrong", e)
}
});
From here, when I run and then select from the dropdown, I receive an error of Cannot POST /table, and nothing shows in my console.log(dbTitle);, so I'm assuming no variable is being sent from my form to the server.
From what I've gathered in using a form vs ul li hyperlinks, there are some differences where the form needs to have method="post", and the server needs to be app.post with req.body instead of req.params. Or maybe this is incorrect?
Thank you for any help you can share.
I figured it out, here's what I needed to do.
Everything was fine on my client db.ejs.
In my server.js, I needed to change app.post('/auradbtable/:dbTitle' to app.post('/auradbtable?:dbTitle'... change the '/' to '?'.
And using const {dbTitle}=req.body; is correct.

Express: POST does not send data - var is not defined

In a view, i am trying to get the data that a user sent, via a form, from another view.
This is the view with the form (i have omitted some EJS stuff to avoid confusion):
<form action="/renderer" method="POST" id="sc-form">
<label for="model">Choose a model:</label>
<select name="model" id="model">
<% data.forEach(function(dat) { %>
<option value="<%= dat %>"> <%= dat %> </option>
<% }); %>
</select>
<input type="submit" value="Render the model!" />
</form>
As you can see, the user selects from a dropdown, and then data is POSTed on /renderer.
So, let's handle this POST request on routes.js:
app.post('/renderer', function(req, res) {
var myModel = req.body.model;
res.render('renderer.ejs', {data: myModel});
});
Pretty basic, we get the data that the form sent and we send it to renderer.ejs as parameters.
Finally, let's grab the data on /renderer.ejs (this is inside a <script> tag):
var modelName = <%- JSON.stringify(data) %>;
And i get this error:
data is not defined
But why is that? Data is the name of the variable that the router sent to the view, as parameter.
This is the third day that i am trying to make POST data appear on another view. If anyone could help i would really appreciate it.
I finally found this.
The form has to contain role="form", or else it wouldn't work.

how make checkbox stay checked and reset in node js

I am working on a small project with checkbox and node js. I need the checked box stay on the screen after I click submit button and reset the form after clicking reset button.How can do that?
ejs code
<form method="post" action="/">
<input type="checkbox" name="preference" value="A">A
<input type="checkbox" name="preference" value="B">B
<input type="checkbox" name="preference" value="C">C
<input type="submit" value="Click to Submit">
<input type="reset" value="Erase and Restart">
</form>
node js
express.get('/', (req, res) => {
res.render('form');
});
express.post('/', (req, res) => {
console.log(req.body);
let checkedValue =req.body.preference;
let output = checkedValue==undefined?`You didn' make selection.`:`The preference iterm on menu is ${checkedValue}`;
res.render('form',{
output:output,
});
});
What's going on is that when you submit your form, the webpage is reloaded, so you lose your checked state. You can either save the values on your server and have them pre-checked using an optional checked flag in your ejs template or you can add some client side javascript to handle the form submission for you by writing and event handler for the submit event on the form.
if you expand your ejs template with a conditional checked value on your inputs, your returned page will have them pre-checked
<input type="checkbox" name="preference" <% if (submittedValue === "A") { %>checked<% } %> value="A">A
Or, here's a super simple bit of javascript that would send the values to your server
document.forms[0].addEventListener('submit', function (e) {
e.preventDefault(); // prevent the form from submitting with a page refresh
const data = { values: [] };
e.target.elements.forEach((formEl) => {
if (formEl.checked) data.values.push(formEl.value);
});
fetch('/urlToProcessYourForm', { method: 'POST', body: JSON.stringify(data) });
});

how can i retrieve objectId of parse server through req.params.id

I am trying to retrieve a parse object with objectId in the show route on nodeJS. Below is my code to help you understand better.
//SHOW route
app.get("/books/:id", function(req, res) {
var Books = Parse.Object.extend("Books");
var query = new Parse.Query(Books);
query.equalTo("objectId", req.params.id);
query.find().then(function(foundBook){
res.render("show", {book: foundBook});
}, function(error) {
res.send("Error: " + error.code + " " + error.message);
});
});
Basically, The req.params.id does not return the objectID. when i try console.log(req.params.id), it returns the Title of the book stored in the database instead of the objectId which is important for linking to the /books/:id page.
Even when i try to retrieve all the objects from the database in the index route, i noticed that <%= book.get('objectId') %> is not displayed on the ejs page.
Please help me out of this. i am a beginner MEAN stack web developer but i am using parse server because the android and web applications would be sharing the same database on parse.com.
Thank You.
<% books.forEach(function(book) { %>
<div class="col-md-3 col-sm-6">
<div class="thumbnail">
<!-- this line of code gets the image content of the array and puts it in the img tag -->
<img src="<%= book.get('coverPictureLink') %>">
<div class="caption">
<h4><%= book.get('Title') %></h4>
</div>
<p>
<!-- This code adds the button and links it to the ID of the campground that was clicked on!-->
More Info
</p>
</div>
</div>
<% }); %>
</div>
Above is sample of the html page for displaying details of a particular book
I finally figured it out. The right way to retrieve object id on the html is book.id not book.get("objectId").
app.get("/books/:id", function(req, res) {
//find the book with provided ID
var Books = Parse.Object.extend("Books");
var query = new Parse.Query(Books);
query.get(req.params.id).then(function(book) {
console.log('retrieved! ' + book.id);
res.render('show', {book: book});
}, function(error) {
console.log('error occured');
res.send('could not be retrieved');
});
});
On the html file,
<p>
More Info
</p>
This is also the same if you are using node.js. with the parse server framework. Using .get('objectId') returns undefined values. Therefore you have to use.
for (i = 0; i < result.length; i++){
console.log('ID:' + result[i].id)
}

How to work with dynamically loaded elements in YUI

I'm currently trying to integrate spring mvc app using YUI3. I was able to call Spring Controller with static href in jsp through YUI, but script is not getting invoked when trying to invoke dynamically generated href.
<script src="http://yui.yahooapis.com/3.14.1/build/yui/yui-min.js"></script>
<script>
YUI().use('io-form', 'json','datatable','node','tabview',function(Y) {
Y.all('#nav a').on('click', function (ev) {
ev.preventDefault();
//main.load(ev.target.get('href'), '#content');
var href = ev.target.get('href');
var url = href.substring(0,href.indexOf('#'));
var idw = href.substring(href.indexOf('#')+1,href.length);
Y.io(url, {
method: 'GET',
on: {
complete: function(id, response) {
answer = Y.JSON.parse(response.responseText);
Y.log(answer);
var main = Y.one('#'+idw);
var node = main.all('li');
if(node.size()===0){
Y.Object.each(answer, function(item, index){
main.append("<li id='"+item+"' class='api-list-item class'><a href='/YUI-2-Spring/getContactDetails/"+item+".html#"+item+"'>"+item+"</a></li>");
});
}
}
}
});
});
//To call controller on clickin of dynamic links
Y.all('#api-Types a').on('click', function (ev) {
ev.preventDefault();
//main.load(ev.target.get('href'), '#content');
var href = ev.target.get('href');
var neturl = href.substring(0,href.indexOf('#'));
var studId= href.substring(href.indexOf('#')+1,href.length);
Y.io(neturl, {
method: 'GET',
on: {
complete: function(id, response) {
answer = Y.JSON.parse(response.responseText);
Y.log(answer);
var main = Y.one('#api-everything');
var node = main.all('li');
if(node.size()===0){
Y.Object.each(answer, function(item, index){
main.append("<li id='"+item+"' class='module-class'><a href='/YUI-2-Spring/getPersonalDetails/"+item+"/"+contId+"'</a>"+item+"</li>");
});
}
}
}
});
});
});
</script>
The first script I'm using for calling controller on tabview selection .Based on that I'm creating a list of String with href inside <ul id="api-Types" class="apis modules"></ul> field. In the next script, I'm trying to invoke the generated links, but script is not getting executed.
<div class="yui3-u-1-4">
<div id="docs-sidebar" class="sidebar apidocs">
<div id="api-list">
<h2 class="off-left">APIs</h2>
<div id="api-tabview" class="yui3-tabview-content">
<ul id="nav" class="tabs">
<li class="yui3-tab yui3-widget yui3-tab-selected">Elements</li>
<li class="yui3-tab yui3-widget">Contact Details</li>
<li class="yui3-tab yui3-widget">All</li>
</ul>
<div id="yui3-tabview-panel">
<ul id="api-elements" class="apis classes">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
</ul>
<ul id="api-Types" class="apis modules">
<input type="search" id="api-filter" placeholder="Type to filter APIs"></ul>
<ul id="api-everything" class="apis search">
<input type="search" id="api-filter" placeholder="Type to filter APIs">
<li class="message">
Begin typing in the search box above to see results.
</li>
</ul>
</div>
</div>
</div>
This is the dynamic list that got generated got from viewsource:
<ul id="api-Types" class="apis modules yui3-tab-panel yui3-tab-panel-selected" role="tabpanel" aria-labelledby="yui_3_14_1_1_1389513296688_62">
<input type="search" id="api-filter" placeholder="Type to filter APIs"><li class="api-list-item class">ABC</li><li id="BCD" class="api-list-item class">BCD</li><li id="CDE" class="api-list-item class">CDE</li><li id="DEF" class="api-list-item class">DEF</li><li id="EFG" class="api-list-item class">EFG</li><li id="FGH" class="api-list-item class">FGH</li></ul>
When I'm clicking on the links, instead of invoking the script, my controller is getting invoked through Dispatcher servlet.
Any help will be appreciated.
To bind events on dynamically added element on DOM you should use 'delegate' to bind event instead of 'on'. It will work.

Resources