req.body.Dates is not defined - javascript

I have 2 drop down menus that are dynamically being populated using 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'
What I have already tried is to pass the selected item from the dropdown to the router, like so:
router.js
router.post('/selection', async (req, res) =>{
try {
var nameFromDB = await conn.query("SELECT DISTINCT pr.Name FROM WFS.Table1 pr WHERE pr.Group = 'Test'");
var dateFromDB = await conn.query('SELECT r.Date FROM WFS.Table2 r');
var tables = ("SELECT * FROM WFS.view v WHERE v.Date= '" + req.body.Dates + "' AND v.Name = '" + req.body.Names + "'");
console.log("SELECT * FROM WFS.view v WHERE v.Date= '" + req.body.Dates + "' AND v.Name = '" + req.body.Names + "'");
res.render('selection', {tables: tables, nameFromDB : nameFromDB , dateFromDB: datesFromDB});
}
catch (err) {
res.status(500)
res.send(err.message)
}
});
This is the output of the console.log :
SELECT top 100 * FROM WFS.view_workRequests_Extended v WHERE v.Revenue_Release_Id = '04/16/2019' AND v.Development_Manager = 'Andrew'
app.js
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use('/', router);
index.ejs
<script>
$(document).ready(function() {
$('#DDD').on('change', function(event) {
var selectedDate = $('#selections option:selected').val();
});
$('#DDN').on('change', function(event) {
var selectedName = $('#selection option:selected').val();
});
$('#submitData').on('submit', function(e){
e.preventDefault();
$.ajax({
type: "POST",
url: "/selection",
data: {selectedDate : selectedDate, selectedName : selectedName },
success: function() {
alert('success');
}
});
});
});
</script>
<form action="/selection" method="POST">
<select class="DateDD" id="DDD" name="Dates">
<% for(var n=0; n < dateFromDB.recordset.length; n++) { %>
<option><%= dateFromDB.recordset[n].Date%></option>
<% } %>
</select>
<select class="NameDD" id="DDN" name="Names">
<% for(var n=0; n < nameFromDB.recordset.length; n++) { %>
<option><%= nameFromDB.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>
After form submit on index.ejs this error gets thrown:
Dates is not defined
I don't know whats causing this error, because I am able to see the name and date in the console being printed. Any help would be appreciated, thank you!

You've intercepted onsubmit event and modified the names of the data sent through ajax
$.ajax({
type: "POST",
url: "/selection",
data: {selectedDate : selectedDate, selectedName : selectedName }, // <-- here
success: function() {
alert('success');
}
});
So you're reading the wrong property in your req.body. You should instead read like:
// for date
req.body.selectedDate
// for name
req.body.selectedName
Also you claim
I am able to see the name and date in the console
The output of console you've put doesn't match the query in the code in question.

This is basic debugging question.
I can advice you to do couple of things like:
Check the browser devTools (network tab) to see if the body payload is being passed to the server.
On the server (express), are you using body parser middleware ? see more here (req.body section).
Try to run nodejs with inspect mode and attach your IDE (VSCode is a good one) and add some breakpoints. Alternatively, you can do some console.logs in order to check what are you getting from the client.
You can simulate a browser request using postman to check the server side and make sure it is working fine.

This is a simple error, so no big deal, frustrating as I know it can be.
I see you using dates, date, Date & Dates. I would look for a line number reference to give me a clue. I would use chrome and developer tools or console.log to see how far I get.
Or, I would use a different name convention like date1, date2, date3, date4 or something that is even more descriptive, so I knew for sure which date was what, then on narrowing down the error, it will be much easier to fix.

Related

Re-rendering an EJS template after jQuery POST request with new data

Update Edited my original code due to errors.
This is my first question posted here so please be gentle. :)
I am using node.js with Express and EJS forms.
What I am trying to achieve is to have an EJS template re-rendered after a jQuery POST request with new data. This is a simplified example of what I am trying to do (my original code includes a lot of fuss, SQL queries and is not properly refactored).
My goal would be to render the same template with different data when pressing a button on the page. What happening currently is when I press the button, the data is there (checking it in console), but the page does not render again with the new data. I am completely out of ideas and been stuck with this for almost a day now.
I know I could do something like
res.send(JSON.stringify(myData));
and build the HTML with a JS script, but it would be nice to be able to use EJS for better readability - my original code includes a lot of HTML elements.
Is it doable at all? Or is this an intended behaviour for rendering with Express? Sorry if I am being clueless, as I am fairly new to web development.
Anyway, here is my code, all ideas are greatly appreciated. Thanks!
test_dynamic.ejs:
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="post" action="/test">
<wrapper>
<h1>
<button id="toggleButton" onclick="toggle()" type="button">Toggle</button>
</h1>
<div>
<% console.log('Should show ' + name + ' with id: ' + id) %>
<li><%=name %></li>
<li><%=id %></li>
</div>
</wrapper>
</form>
</html>
<script>
var shouldShowJohn = false;
function toggle () {
var postData = {};
shouldShowJohn = !shouldShowJohn;
if (shouldShowJohn)
postData.mode = 1;
else
postData.mode = 2;
$.post('http://localhost:3000/test', postData, function (data) {
$('#toggleButton').html('').append('Showing ' + postData.mode);
});
}
</script>
routes.js:
router.get('/test', (req, res) =>{
var obj = {
name: 'DefaultName',
id: 1
}
res.render('test_dynamic', obj);
})
router.post('/test', (req, res) => {
var obj = {};
console.log('req.body.mode: ' + req.body.mode);
if (req.body.mode == 1)
obj = {
name: 'John',
id: 2
}
else
obj = {
name: 'Karl',
id: 3
}
res.render('test_dynamic', obj)
})
Please take a look at the example I've included via link below. There is a lot wrong with your HTML above, but I will focus on your question. There are several ways you can solve this problem so this is the simplest.
As stated in my comment, the workflow is:
Send POST
Respond with success/failure
If success, redirect/re-request same page from server.
Note I am not addressing EJS because when you request the page from the server that will happen naturally as you have laid out above.
Step 1: So in the sample, index.js is the server, I have basic routing to two files, index.html and page2.html. I did this so you can see the change happening. Next, in the index.html file I have a button that generates the POST request via jQuery. This takes care of step 1.
Step 2: index.js accepts the post request to /test and responds with a simple string "success" (you could respond with anything)
Step3: In index.html the $.post() handler tests for the string 'success' and the redirects to page2.html. In your scenario this would redirect back to the same page. I made it different so you could realize the change easily.
Solution
https://repl.it/#randycasburn/SimplePostResponseRedirect
Here is my solution, partially based on Randy's answer.
test_dynamic.ejs:
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body id="myBody">
<form method="post" action="/test">
<wrapper>
<h1>
<button id="toggleButton" onclick="toggle()" type="button">Toggle</button>
</h1>
<div>
<% console.log('Should show ' + name + ' with id: ' + id) %>
<li><%=name %></li>
<li><%=id %></li>
</div>
</wrapper>
</form>
</body>
</html>
<script>
var shouldShowJohn = false;
var postData = {};
postData.mode = 'toggle';
function toggle () {
$.post('http://localhost:3000/test', postData, function (data) {
$('#toggleButton').html('').append('Showing ' + postData.mode);
$('#myBody').html(data);
});
}
</script>
routes.js:
router.get('/test', (req, res) =>{
var obj = {
name: 'DefaultName',
id: 1
}
res.render('test_dynamic', obj);
})
var currentMode = 1;
router.post('/test', (req, res) => {
var obj = {};
console.log('req.body.mode: ' + req.body.mode);
if (req.body.mode == 'toggle')
if (currentMode < 3)
currentMode++;
else
currentMode = 1;
if (req.body.mode == 1)
obj = {
name: 'John',
id: 2
}
else
obj = {
name: 'Karl',
id: 3
}
res.render('test_dyanmic', obj)
})

php/ajax JSON respone returns [object, Object] once parsed

When I try to parse a response from an AJAX request as JSON, I get [object, Object] values instead of the actual ones returned before parsing the response. What could I have done wrong?
I have one script named "apply.php" which has the a short application and an AJAX request called when the user selects a town. There is another script named "suburb.php" which retrieves stored suburbs in the database that are under the selected town. The second script is called when the users selects/changes a town.
In the "apply.php" script I have a JavaScript alert that display the response, which I then parses as JSON. After passing the response, [object, Object] is returned instead of the actual values, thus disabling me from reading the JSON key values.
Using the values without parsing them does not help either. I tried checking for question that relate to my problem without any luck.
Your assistance will be greatly appreciated.
apply.php
<?php
$dbcon = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
?>
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Accomodation Application</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
</head>
<style>
form div {
margin-bottom: 20px;
}
</style>
<body>
<div>
<div>
<form>
<p>Refresh</p>
<div><label for="applicant-name">First Name</label><br /><input type="text" name="name" id="applicant-name"></div>
<div><label for="applicant-surname">Surname</label><br /><input type="text" name="surname" id="applicant-surname"></div>
<div><label for="applicant-identity">Smart ID Number</label><br /><input type="text" name="surname" id="applicant-identity"></div>
<div id="town">
<label for="applicant-town">Town</label><br />
<select name="town" id="applicant-town"><option value="0">-- Select Town --</option>
<?php
$towns = mysqli_query($dbcon, "SELECT town_id, town_name FROM towns");
while($town = mysqli_fetch_array($towns)){
$town_id = $town['town_id'];
$town_name = $town['town_name'];
echo("<option value=\"$town_id\">$town_name</option>");
}?>
</select>
</div>
<div id="suburb">
<label for="applicant-suburb">Suburb</label><br />
<select name="suburb" id="applicant-suburb">
<option value="0">-- Select Suburb --</option>
</select>
</div>
<button type="submit">Submit</button>
</form>
</div>
</div>
<script>
$(document).ready(function(){
$('#applicant-town').change(function(){
var suburb_town = $(this).val();
$.ajax({
type: "GET",
url: "suburbs.php",
data: {town: suburb_town}
})
.done(function(data){
alert(data);
var burbs = JSON.parse(data);
alert(burbs); // e.g. [{"1":"Halfway House"},{"2":"Noordwyk"},{"3":"Vorna Valley"}]
$(burbs).each(burbs, function(key, value){
$('#applicant-suburb').append('<option value="'+key+'">'+value+'</option>');
});
})
.fail(function(){
alert('There is an error somewhere.');
});
});
});
</script>
</body>
</html>
suburbs.php
<?php
$dbcon = new mysqli (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if(isset($_GET['town'])){
$town_suburbs = array();
$town_id = htmlspecialchars($_GET['town']);
$suburbs = mysqli_query($dbcon, "SELECT suburb_id, suburb_name FROM suburbs WHERE suburb_town = $town_id");
while($suburb = mysqli_fetch_array($suburbs)){
$suburb_id = $suburb['suburb_id'];
$suburb_name = $suburb['suburb_name'];
$town_suburbs[] = array($suburb_id => $suburb_name);
}
echo json_encode($town_suburbs);
}
?>
Why not use dataType: "json" in your statement ajax?
$.ajax({
type: "GET",
url: "suburbs.php",
data: {town: suburb_town},
dataType: 'json'
})
Thus instead of making an "alert ()" you must make a "console.log" and analyze the content through the Javascript console your browser.
The Alert feature only shows "String" and therefore when attempting that shows you the content. The representation of an object in string is [object]. Therefore instead of console.log occupies alert ().
update: You can use alert (JSON.stringify (data)) to display the string in a alert.
update2: Your code will looks
$.ajax({
type: "GET",
url: "suburbs.php",
data: {town: suburb_town},
dataType: 'json'
})
.done(function(data){
console.log(data)
});
})
So first off from the comments you can see what the issue is. However, you may want to use your "id" for something so with that in mind you could do the following.
$town_suburbs[] = array($suburb_id => $suburb_name);
You could change that to
array_push($town_suburbs, array("id" => $suburb_id, "name" => $suburb_name));
Then on your javascript side...
$(burbs).each(burbs, function(key, value){
$('#applicant-suburb').append('<option value="'+key+'">'+value+'</option>');
});
That could change to:
$(burbs).each(function(){
$('#applicant-suburb').append('<option value="'+ this.id +'">'+ this.name +'</option>');
});
Perhaps, it was already saved as [Object Object]?
Ensure that,
to decode a JSON string, use JSON.parse()
to encode a JSON string, use JSON.stringify
Hope this helps.
If your "E.G." is correct, then you are not looping (in javascript) in the correct way.
This:
$(burbs).each(burbs, function(key, value){
$('#applicant-suburb').append('<option value="'+key+'">'+value+'</option>');
});
Should not work, because you have to loop an array of objects, therefore you first have to loop the array and, then, the objects:
for (var i = 0; i < burbs.length; ++i) {
$.each(burbs[i], function(key, val) {
$('#applicant-suburb').append('<option value="'+key+'">'+val+'</option>');
});
}
According to your example, you can check this fiddle: http://jsfiddle.net/5yaj7La0/2/
As long as your current output has this structure:
[{"1":"Halfway House"},{"2":"Noordwyk"},{"3":"Vorna Valley"}];
You DON'T need to change your PHP code but if the output is different from that (it shouldn't, though), you may need to change your PHP code too.
HTML output :
(output is related to the fiddle, feel free to edit the names and tag and whatever, the important thing here is the Javascript).
If you get [Object object] by doing :
var burbs = JSON.parse(data);//alerting this will definitely present [Object object]
Then everything seems to be fine.
You are parsing the data and this will be converted to a json object.
If you want to view the response data use :
var burbs = JSON.stringify(data);//converts the object to a string
alert(burbs);
Also probably you want to get the values by accessing the keys of each object within the object array:
//lets imagine this is our response data, which can also be the response data you parsed with JSON.parse(data);
var data = [{"1":"Halfway House"},{"2":"Noordwyk"},{"3":"Vorna Valley"}];
function iterate(data)
{
for(var i=0;i<data.length;i++)
{
for(var i=0;i<data.length;i++)
{
for(var key in data[i])
{
var value = data[i][key];
$('#applicant-suburb').append('<option value="'+key+'">'+value+'</option>');
}
}
}
}
Can the problem be with the fact that you are missing a header() statement in your suburb.php file?
Something like

Ajax POSTS not updating screen content

So I have a "scenario", made up of lots of "forms" which contain lots of "events" and "data" etc. To populate all this information I have this in the page to run once the page is finished
$(document).ready(function() {
var scenarioID = ${testScenarioInstance.id}
var myData = ${results as JSON}
populateFormData(myData, scenarioID);
});
This then calls the functions below (the first calls the second, done like this as I had an issue where as it was ajax the variables in the loop were updating before things were being appended and so everything ended up in the last sub table): -
function populateFormData(results, scenarioID) {
$table = $('#formList')
for ( var i in results) {
var formIDX = (results[i]["forms_idx"])
var formID = (results[i]["form_id"])
appendSubTable(formIDX, scenarioID, $table, formID);
}
}
function appendSubTable(formIDX, scenarioID, $table, formID) {
var url = "http://localhost:3278/FARTFramework/testScenario/ajaxPopulateSubTables"
$.post(url, {
formIDX : formIDX, scenarioID : scenarioID, formID :formID
}, function(data) {
var $subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
$subTable.append(data)
}).fail(function() {
alert("it failed!")
});
}
This then goes off grabs the data from the controller like so..
def ajaxPopulateSubTables(int formIDX, int scenarioID, int formID) {
def db = new Sql(dataSource)
String mySQL = "Loads of SQL STUFF"
def subTableResults = db.rows(mySQL)
render(template: "subTableEntry", model: [subTableResults:subTableResults, formID:formID, formIDX:formIDX])
}
and fires it at the gsp:
<colgroup>
<col width="150"/>
<col width="350"/>
<col width="350"/>
<col width="350"/>
</colgroup>
<g:if test="${subTableResults != null && !subTableResults.isEmpty()}">
<tr>
<th>eventIDX</th>
<th>eventID </th>
<th>objID</th>
<th>testVal</th>
</tr>
</g:if>
<g:each in="${subTableResults}" status = "i" var="item">
<tr id = ${i} class="${((i) % 2) == 0 ? 'even' : 'odd'}" name="main">
<td>${item.events_idx}</td>
<td>${item.type}</td>
<td>${item.object_description}</td>
<td><g:textField id = "testData[${formIDX}:${formID}:${i}]" name="testData[${formIDX}:${formID}:${i}]" value="${item.value}" optionKey="id" /></td>
</tr>
</g:each>
Before then jamming it into the relevant sub table.
The problem is, sometime when I load up a page not all the sub tables are filled out, but if I hit F5 to refresh the page this then seems to fix the issue... Although not always, sometimes I then get a different section not refreshing :(
I put a println into the controller to see if all the SQLs were being fired off but it always returns all the individual form SQL strings fine...
Looking in firebug all the POSTs are coming back fine but the page just isn't updating...
Any suggestions or ideas as to what might be causing this would be appreciated, I'm at a loss..
I also tried updating my appendSubTable function where the post is to include a fail in case something was failing, but this isn't hit either, have updated code above to show this
Oddly I altered the post function slightly to the below, moving the finding of the table to the beginning of the function rather than within the post itself and that seems to have done the trick, although why I'm not sure... Whether someone can explain why this is or not I'd be interested to know why!
function appendSubTable(formIDX, scenarioID, $table, formID) {
var $subTable = $table.find("#" + formIDX).find('td:eq(1)').find("div").find("table")
var url = "http://localhost:3278/FARTFramework/testScenario/ajaxPopulateSubTables"
$.post(url, {
formIDX : formIDX, scenarioID : scenarioID, formID :formID
}, function(data) {
$subTable.append(data)
}).fail(function() {
alert("fail")
});
}

Modifying Replicated EditorTemplates with Javascript

I have an Editor Template which contains a table row with (among other stuff) a dropdown/combobox to select a currency. This edit template is shown many times on the same View and it's possible for a user to add these rows as many times as he wants.
I want changes on a row's dropdown to reflect in an EditorFor (the currency's rate) on the same row, so I've added a onchange html parameter:
<td>
#*#Html.LabelFor(model => model.Currency)*#
#Html.DropDownListFor(model => model.Currency, new SelectList(Model.CurrencyList, "Code", "Code"), new { onchange = "updateCurrency(this)" })
#Html.ValidationMessageFor(model => model.Currency)
</td>
My javascript function makes an ajax call to retrieve the rate for the selected currency:
function updateCurrency(elem) {
alert("Currency changed!")
$.ajax({
type: "GET",
url: "Currency?code=" + elem.value,
success: function (msg) {
// The Rate field's Id:
var RateId = "#Html.ClientIdFor(model=>model.Rate)" // // Halp, problem is here!
document.getElementById(RateId).value = msg;
}
});
}
My problem is that
var RateId = "#Html.ClientIdFor(model=>model.Rate)"
has that Html helper which is server-side code. So when i view the page's source code, the javascript code is replicated (once for each row) and all the var RateId = "#Html.ClientIdFor(model=>model.Rate)" are pointing to the most recently added column's EditorFor.
Probably my way of attempting to solve the problem is wrong, but how can I get my javascript code to update the desired field (i.e. the field in the same row as the changed dropdown list).
I believe that one of the problems is that I have the javasript on the Editor Template, but how could I access stuff like document.getElementById(RateId).value = msg; if I did it like that?
Thanks in advance :)
Figured it out. Hoping it helps somebody:
In my view:
#Html.DropDownListFor(model => model.Currency, new SelectList(Model.CurrencyList, "Code", "Code"), new { #onchange = "updateCurrency(this, " + #Html.IdFor(m => m.Rate) + ", " + #Html.IdFor(m => m.Amount) + ", " + #Html.IdFor(m => m.Total) + ")" })
In a separate JavaScript file:
function updateCurrency(elem, RateId, AmountId, TotalId) {
var cell = elem.parentNode // to get the <td> where the dropdown was
var index = rowindex(cell) // get the row number
// Request the currency's rate:
$.ajax({
blah blah blah .........
(RateId[index - 1]).value = 'retreived value'; // Set the rate field value.
});
}
Seems to be working so far.

Dynamically updating html.listBox in MVC 1.0?

The client will choose an item from a dropDown list, this newly selected value will then be used to find assets linked to that selected item, these assets will then be loaded into the listBox.
This sounds simple enough, and I'm aware I could use a partial View but it seems overkill for just updating one component on a form.
Any
I've done this in MVC 1.0 myself. I used an onchange on the first drop down which called an action using the value selected. That action returned a JSON result. The jQuery script which called that action then used the JSON to fill the second drop down list.
Is that enough explanation, or would you like help writing the javascript, the action, or both?
Inside your view:
<%= this.Select("DDLName").Attr("onchange", "NameOfJavascriptFunction();") %>
<%= this.MultiSelect("ListBoxName") %>
The javascript will look like this:
function NameOfJavascriptFunction() {
var ddlValue = $("DDLName").val();
jQuery.ajax({
type: 'GET',
datatype: 'json',
url: '/Controller/Action/' + dValue,
success: updateMultiSelect
});
}
function updateMultiSelect(data, status) {
$("#ListBoxName").html("");
for(var d in data) {
$("<option value=\"" + data[d].Value + "\">" + data[d].Name + "</option>">).appendTo("#ListBoxName");
}
}
Finally, the action is something like this (put this in the controller and action from the first javascript):
public ActionResult Action(int id) //use string if the value of your ddl is not an integer
{
var data = new List<object>();
var result = new JsonResult();
this.SomeLogic.ReturnAnEnumerable(id).ToList().ForEach(foo => data.Add(new { Value = foo.ValueProperty, Name = foo.NameProperty }));
result.Data = data;
return result;
}
Feel free to ask follow up questions if you need any more explanation.

Categories