I'm getting JSon data from my server and building a table with this data. The last column of the table is a button that will grab the fields from the selected row to populate another fields, but it is returning: ReferenceError: response.DATA is not defined.
response = JSON.parse(response);
$('.myDiv').empty();
// Header
var table = '<table class="table table-striped"><thead><tr><th>First Name</th><th>Last Name</th><th>City</th><th>State</th><th>ZIP</th><th>Action</th></tr></thead><tbody>';
var i;
for(i=0; i<response.ROWCOUNT; i++){
table += '<tr>';
table += '<td>' + response.DATA.PROVIDERFIRSTNAME[i] + '</td>';
table += '<td>' + response.DATA.PROVIDERLASTNAME[i] + '</td>';
table += '<td>' + response.DATA.PROVIDERCITY[i] + '</td>';
table += '<td>' + response.DATA.PROVIDERSTATE[i] + '</td>';
table += '<td>' + response.DATA.PROVIDERPOSTALCODE[i] + '</td>';
table += '<td><input type="button" class="btn btn-primary" value="select" onClick="setData(response.DATA, i);" /></td>';
table += '</tr>';
}
table += '</tbody></table>';
$('.myDiv').append(table);
My setData function:
function setData(data, pos){
console.debug(data.PROVIDERFIRTNAME[pos]);
}
You're using an inline handler, and an inline handler can only reference global variables. Attach the listener properly using Javascript instead, so that it can reference the variables (most importantly, response and i) properly. Also make sure i is block scoped with let, rather than function-scoped.
You can also consider using template literals to make the code a lot more readable:
// Header
const $table = $('<table class="table table-striped"><thead><tr><th>First Name</th><th>Last Name</th><th>City</th><th>State</th><th>ZIP</th><th>Action</th></tr></thead><tbody></tbody>');
// make sure to use "let i" here
for (let i = 0; i < response.ROWCOUNT; i++) {
const $row = $(`
<tr>
<td>${response.DATA.PROVIDERFIRSTNAME[i]}</td>
<td>${response.DATA.PROVIDERLASTNAME[i]}</td>
<td>${response.DATA.PROVIDERCITY[i]}</td>
<td>${response.DATA.PROVIDERSTATE[i]}</td>
<td>${response.DATA.PROVIDERPOSTALCODE[i]}</td>
<td>${response.DATA.PROVIDERPOSTALCODE[i]}</td>
<td><input type="button" class="btn btn-primary" value="select"/></td>
</tr>
`);
$row.find('input').on('click', () => {
console.debug(response.DATA.PROVIDERFIRSTNAME[i]);
});
$table.find('tbody').append($row);
}
$('.myDiv').append(table);
Spelling matters - make sure to use PROVIDERFIRSTNAME instead of PROVIDERFIRTNAME.
Inline handlers are pretty universally considered to be poor practice - best to avoid them whenever possible.
Related
I have a problem concerning multiple file uploads in javascript. I am trying to create my own multiple file upload by dynamically adding inputs. This is all easy as pie, but the problem is that whenever I add a new , my previous input-fields of the type "file" get reset.
If I remove the last lines of code where I alter the innerHTML of my parent div, the values of my do not get reset. Does anyone know how this problem can be solved? The javascript code can be found below. Thanks in advance.
if(document.getElementById("upload_queue").innerHTML.indexOf(_item) == -1)
{
var _row = "<tr id='queue_row_" + items_in_queue + "'>";
_row += "<td>";
_row += "<div class='remove_uploaded_image' onclick='remove_from_queue(" + items_in_queue + ")'></div>";
_row += "</td>";
_row += "<td>";
_row += _item;
_row += "</td>";
_row += "</tr>";
document.getElementById("upload_queue").innerHTML += _row;
document.getElementById("upload_image_" + items_in_queue).style.display = "none";
items_in_queue++;
document.getElementById("uploader_holder").innerHTML +=
'<input id="upload_image_' + items_in_queue +
'" name="upload_image_' + items_in_queue + '" accept="image/jpeg" type="file"' +
'onchange="add_to_upload_queue()" style="display: inline;" />';
}
Yeah... you're going to want to use appendChild instead of modifying the inner HTML:
var myInput = document.createElement("INPUT");
// do stuff to my input
var myContainer = document.getElementById("uploader_holder");
myContainer.appendChild(myInput);
That's the general gist of what you have to do - let me know if you need somethign more specific, but it looks like you've got a good hold on JS already... You're going to want to do that in almost all cases rather than setting inner HTML... So, building your TR as well... you'll have to append the TD to the TR, you'll have to append the TD with your input, you'll have to append your targeted table with the TR, etc.
Im trying to add input where you can select different options for a location. my issue is that its messing up the table and it just does not see me new input option that i've added. I can list other files or pictures if needed.
var items = 0;
function addItem() {
items++;
var html = "<tr>";
html += "<td>" + items + "</td>";
html += "<td><input type='number' name='idNumber[]'></td>";
html += "<td><input type='text' name='itemName[]'></td>";
html += "<td><input type='number' name='itemQuantity[]'></td>";
html += "<td><select name='itemLocation[]' id='location'><option value="Shop" name="Shop">Shop</option></select></td>";
html += "<td><input type='text' name='itemIndex[]'></td>";
html += "<td><button type='button' onclick='deleteRow(this);'>Delete</button></td>"
html += "</tr>";
Just trying to change to location button to a multiple choice selection
you have double quotes inside your string which is breaking your template
to avoid this kind of error you should use template literals its fully supported
Note it is backtick (`) not singlequote (')
see example
var value = "new entry"
var tr = `
<tr>
<td>${value}</td>
<td>${value}</td>
<td>${value}</td>
<td>${value}</td>
<td>${value}</td>
</tr>
`
this is for a web app that will take in a survey I am using firebase. What I need help in is when the app is exporting the data into a table it grabs the data but won't is able to push it to the table any help would be appreciated. Since the HTML code is a long one I will only put the table portion:
the table portion of the HTML file
<div id = "table">
<pre id = "snap-test"></pre>
<table id ="File-Table" class="table">
<thead>
<tr>
'<td><button onclick = "DeleteTabele()" id = "Delete-btn">Delete File</button></td>'
</tr>
</thead>
<button onclick ="Return()" id= "Log-btn" type="submit" class="btn btn-">Add a new File</button>
</table>
</div>
the Table.js file
var table = document.getElementById("File-Table");
const file = $("#File").val();
var requests = [];
function Export(){
//calls the file id in the HTML element
$("#Survey-Page").hide();
$("#File-Table").show();
$("#Log-btn").show();
var result = [];
//calls the database from the firebase known as users then using a function we nest a snapshot in it for later
firebase.database().ref('/users/').once('value').then(function(snapshot){
//if snapshot is empty then the window will alert
if (snapshot.val() == null){
alert("Does not exist");
}
// if the snapshot is full then it will genereate a table based on the snapshot value of the database
else {
console.log(snapshot.val());
let result = snapshot.val()
for(let k in result){
this.requests.push({
id: k,
value: result[k]
});
}
var MyTable = '<tr>' +
'<td>' + snapshot.val().txtName +'</td>' +
'<td>' + snapshot.val().txtEmail +'</td>' +
'<td>' + snapshot.val().FileName + '</th>' +
'<td><button id = "Email-btn">Send Survey</button></td>' +
'<td><button onclick = "DeleteTabele()" id = "Delete-btn">Delete File</button></td>' +
'</tr>';
MyTable += "</tr></table>";
table.innerHTML = MyTable;
}
console.log(snapshot.val());
});
From the code you have published, the more probable cause is that your reference is referencing a node of multiple users and not a specific user.
firebase.database().ref('/users/')
To confirm this assumption we need to see your database structure. Can you edit you post?
However, let's imagine this assumption is correct. Then you have two solutions:
If you want to display the value of ONE user which is under the users node, you have to change the reference and point to this user, e.g.:
firebase.database().ref('/users/' + userID)
Then the rest of the code will work normally
If you want to display in your table the entire list of users (one by row) you have to loop over the results of the query, as follow:
firebase.database().ref('/so').once('value').then(function(snapshot){
var MyTable;
snapshot.forEach(function(childSnapshot) {
MyTable += '<tr>' +
'<td>' + childSnapshot.val().txtName +'</td>' +
'<td>' + childSnapshot.val().txtEmail +'</td>' +
// ...
'<td><button id = "Email-btn">Send Survey</button></td>' +
'<td><button onclick = "DeleteTabele()" id = "Delete-btn">Delete File</button></td>' +
'</tr>';
});
table.innerHTML = MyTable;
});
See the doc here: https://firebase.google.com/docs/database/web/lists-of-data#listen_for_value_events
In addition, if I may, you could have a look at this SO post: HTML : draw table using innerHTML which shows some best practices for writing rows of a table in "simple" JavaScript.
Is there a way to build dynamically a table-like structure from a data-set on websites (in javascript)?
In pseudo-code something like:
function pseudo(dataset) {
<table>
<th>dataset.name, dataset.id</th>
foreach dataset.schedular.array as a {
<tr><td>a.start_time</td><td>a.end_time</td><td>a.client.name</td></tr>
}
</table>
}
and executed like:
<div>
<script>pseudo(json[employee[0]]);</script>
</div>
In php i used smarty-templates to "fill" data into similar masks, now i need something similar in javascript.
Are jquery widgets or plugins that what i m looking for? And where can i find helpful tutorials or books?
your html page:
<div id="dataToDisplay"></div>
your java script function:
function pseudo(dataset) {
var tableContents = "<table>";
tableContents = tableContents+ "<th>"+dataset.name, dataset.id+"</th>";
foreach dataset.schedular.array as a {
tableContents =tableContents + "<tr><td>"+a.start_time+"</td><td>"+a.end_time+"</td><td>"+a.client.name+"</td></tr>";
}
tableContents = tableContents + "</table>";
document.getElementById("dataToDisplay").innerHTML = tableContents;
}
I use jQuery and the following construct. employees is an JS array of objects. The HTML table is prepared like this:
<table id="clients">
<thead><tr><th>Start</th><th>End</th><th>Name</th></tr></thead>
<tbody></tbody>
</table>
Then the following jQuery-loop using each is used to append the lines:
$.each(employees, function(index, employee){
$('#clients > tbody').append(listItem(index, employee));
});
where listItem() is a function that returns the table line. Of course, this could be done more elegantly:
function listItem(index, employee) {
var item = '<tr>';
item += '<td>' + employee.start_time + '</td>';
item += '<td>' + employee.end_time + '</td>';
item += '<td>' + employee.name + '</td>';
item += '</tr>';
return item;
}
Take a look at "jqGrid"
http://www.trirand.com/blog/
it's a plugin which takes JSON and biulds tables from it. However it uses jQuery.
I have a code to populate a table using Javascript as:
var myResponse = document.getElementById("jsonPlaceHolder");
myResponse.innerHTML += "<table border=1> <tr> <td> User Id </td> <td> Question </td> <td> Link Question </td> </tr>";
for (var i = 0; i < 25; i++) {
myResponse.innerHTML += "<tr>"
myResponse.innerHTML += "<td>" + jsonObj[i]["user_id"] + "</td>";
myResponse.innerHTML += "<td>" + jsonObj[i]["text"] + "</td>";
myResponse.innerHTML += "</tr>"
}
myResponse.innerHTML += "</table>";
Problem with this code is when I run this table is not continued inside for loop. If I add
myResponse.innerHTML += "<table><tr>"
inside my for loop, table is created. Isn't this bit odd?,
since i am using += to add to current innerHTML of the DOM element.
One of the most misunderstood thing about innerHTML stems from the way the API is designed. It overloads the + and = operators to perform DOM insertion. This tricks programmers into thinking that it is merely doing string operations when in fact innerHTML behaves more like a function rather than a variable. It would be less confusing to people if innerHTML was designed like this:
element.innerHTML('some html here');
unfortunately it's too late to change the API so we must instead understand that it is really an API instead of merely an attribute/variable.
When you modify innerHTML it triggers a call to the browser's HTML compiler. It's the same compiler that compiles your html file/document. There's nothing special about the HTML compiler that innerHTML calls. Therefore, whatever you can do to a html file you can pass to innerHTML (the one exception being that embedded javascript don't get executed - probably for security reasons).
This makes sense from the point of view of a browser developer. Why include two separate HTML compilers in the browser? Especially considering the fact that HTML compilers are huge, complex beasts.
The down side to this is that incomplete HTML will be handled the same way it is handled for html documents. In the case of elements not inside a table most browsers will simply strip it away (as you've observed for yourself). That is essentially what you're trying to do - create invalid/incomplete HTML.
The solution is to provide innerHTML with complete HTML:
var htmlString = "<table border=1> <tr> <td> User Id </td> <td> Question </td> <td> Link Question </td> </tr>";
for (var i = 0; i < 25; i++) {
htmlString += "<tr>"
htmlString += "<td>" + jsonObj[i]["user_id"] + "</td>";
htmlString += "<td>" + jsonObj[i]["text"] + "</td>";
htmlString += "</tr>"
}
htmlString += "</table>"
myResponse.innerHTML += htmlString;
Use the DOM API to manipulate the DOM:
var myResponse = document.getElementById("jsonPlaceHolder");
var table = document.createElement('table'),
headings = ["User ID", "Question", "Link Question"];
table.style.border = "1";
var r = table.insertRow(-1);
for (var i = 0; i < 3; i++) {
(function(){
return r.insertCell(-1);
})().innerHTML = heading[i];
}
for (var i = 0; i < 25; i++) {
r = table.insertRow(-1);
var userid = r.insertCell(-1),
text = r.insertCell(-1);
userid.innerHTML = jsonObj[i]["user_id"];
text.innerHTML = jsonObj[i]["text"];
}
myResponse.appendChild(table);