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.
Related
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.
I have a small web application setup on google sheets which have almost 10k rows and 9 columns.
currently, I took all the data from Google sheets and putting it on an HTML Table and Then I have few inputs through which I filter the table using event listener.
As you could have guessed already it is taking too much of memory since it is on the client side and loading and filtering are slow.
Earlier I was having an interactive filter with an event listener on each key press I have changed it to "Enter" key since it was taking too much time for first two or three characters.
Script on index.HTML
<script>
//global variables
var rows = []; //rows
var currentOrder = 'ascending'; //sorting order
var inputFilter = document.getElementById('partNum'); //input field for ItemName
var inputFilterDes = document.getElementById('partDes'); //input field for description
var nameTable = document.getElementById('table'); //html table
//load function being used for pulling data from google sheet
function load() {
//calling get data function with array and filter array inside
google.script.run
.withSuccessHandler(function(response) {
//response function will be separted into column values
rows = response.map(function(element) {
//all the elements converted into columns
return {
itemCode: element[0],
itemName: element[1],
itemDescription: element[2],
inStock: element[3],
committed: element[4],
onOrder: element[5],
available: element[6],
warehouse: element[7]
};
});
//rows mapping finished
renderTableRows(rows);
//initial load finished here
//filter section starts
//Item name filter
inputFilter.addEventListener('keyup', function(evt) {
if (evt.keyCode === 13) {
// Cancel the default action, if needed
evt.preventDefault();
var filter = evt.target.value.toString().toLowerCase();
}
var filteredArray = rows.filter(function(row) {
return row.itemName.toString().toLowerCase().includes(filter);
});
renderTableRows(filteredArray);
});
//description filter
inputFilterDes.addEventListener('keyup', function(evt) {
if (evt.keyCode === 13) {
// Cancel the default action, if needed
evt.preventDefault();
var filterDes = evt.target.value.toString().toLowerCase();
}
var filteredArrayDes = rows.filter(function(row) {
return row.itemDescription.toString().toLowerCase().includes(filterDes);
});
renderTableRows(filteredArrayDes);
});
})
.getData("SAP"); //pull data from defined sheet
}
//retruing array values in HTML table and placing them in page
function renderTableRows(arr) {
nameTable.innerHTML = arr.map(function(row) {
return '<tr>' +
'<td>' + row.itemCode + '</td>' + '<td>' + row.itemName + '</td>' +
'<td>' + row.itemDescription + '</td>' + '<td>' + row.inStock + '</td>' +
'<td>' + row.committed + '</td>' + '<td>' + row.onOrder + '</td>' + '<td>' +
row.available + '</td>' + '<td>' + row.warehouse + '</td>' + '</tr>';
}).join('');
};
load();
</script>
My code.gs
function doGet(e) {
if (!e.parameter.page) {
// When no specific page requested, return "home page"
return HtmlService.createTemplateFromFile('index').evaluate().setTitle("My Web App");
}
// else, use page parameter to pick an html file from the script
return HtmlService.createTemplateFromFile(e.parameter['page']).evaluate();
}
function getData(sheetName) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
return sheet.getSheetValues(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
}
function getScriptUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
I tried to move it on the server side using the following but failed
EDIT : Removed my Server side atempt code as i think it will create confusions.
I'm not a coder so please excuse me if it sounds silly or unorganized.
SO I am trying to increase the speed and for this, I want to Move scripts server-side however I am not fully confident it will help me or not so I am open to any other methods to improve the speed of application.
Apart from moving map() to async server call, you can optimize the client-side code by creating an ordering function that works over DOM. Currently, each time a keyup event is fired, you rerender the whole table (10K iterations each time if I understand the Spreadsheet size correctly).
First, access your table's children (assuming it is constructed with both <thead> and <tbody> elements: var collection = nameTable.children.item(1).children (returns HtmlCollection of all the rows).
Second, iterate over rows and hide ones that do not satisfy the filtering criteria with hidden property (or create and toggle a CSS class instead):
for(var i=0; i<collection.length; i++) {
var row = collection.item(i);
var cells = row.children;
var itemName = cells.item(1).textContent; //access item name (0-based);
var itemDesc = cells.item(2).textContent; //access item description (0-based);
var complies = itemName==='' && itemDesc===''; //any criteria here;
if( complies ) {
row.hidden = false;
}else {
row.hidden = true;
}
}
Third, move the renderTableRows() function to server async call as well, since you render your table rows with string concatenation (instead of createElement() on document) with htmlString.
Useful links
Document Object Model (DOM) reference;
Server-client communication in GAS reference;
Best practices for working with HtmlService;
I have this jQuery function were I create a table:
function propertyView(values) {
// build the table
var frame = '<fieldset id = "propertiesValueArea" style="border: solid 1px #6b6b6b;">';
var content = frame + smallHeader + '<table data-role="table" id="propertiesList"><thead><tr></tr></thead>';
$.each($(values), function () {
var data1 = this.RealValue.FieldValue;
var data2 = this.RealValue.Id;
//create tables row
content += '<tr data-id=' + this.Id + '>';
content += '<td style="vertical-align: inherit;text-align:center;"><label for="">' + this.FieldName + '</label></td>';
if (this.FieldValue.indexOf(',') > -1) {
content += '<td style="text-align:center;"><select>';
this.FieldValue.split(',').forEach(function (item) {
if (data1 === item) //Here data1 is undefined!!!
{
content += '<option selected="selected" value="">' + item + '</option>';
}
else {
content += '<option value="">' + item + '</option>';
}
})
content += '</select></td>';
}
else {
content += '<td style="text-align:center;"><input type="text" id="propFieldName" data-id="' + this.Id + '" value="' + congiValue(this.FieldValue, this.RealValue) + '"/>';
}
content += '</tr>';
});
content += '</table>';
content += '</fieldset>'
return content;
}
Inside outter each function I create 2 variables:
var data1 = this.RealValue.FieldValue;
var data2 = this.RealValue.Id;
I try to create this variable inside inner each:
if (data1 === item) //Here data1 is undefined!!!
But on this row I get this error:
Uncaught ReferenceError: data1 is not defined
Any idea why data1 is undefined?
It can be undefined only because this.RealValue.FieldValue or this.RealValue is undefined
It looks like
var data1 = this.RealValue.FieldValue; //it's value is undefined
this.FieldValue //it's value is undefined
try to
console.log(this.FieldValue)
console.log(data1)
After that you can easily found where you are getting an error and why. Else everything looks fine with your code.
I have encountered similar problem before. It took me several hours to discover the problem. Now that aside there some things which is not clear here.
is the value coming from another function's operation? If
this.RealValue.FieldValue;
is coming from e.g. a result of maybe another function then you would need to use async/await to ensure that the function completes its operation and there is data in this.RealValue.FieldValue before you move on to the next line of code.
Maybe the this.RealValue.FieldValue itself does not have any thing assigned to it outside of the function itself.
In order to help you we would need a complete code. If you think your code is too private then you can go through it by trying what #Negi Rox said earlier.
Put console.log(this.RealValue.FieldValue) at various strategic locations in your code to determine when it was assigned a value.
What I am trying to do is retrieve the information passed from a previous page through and display this within a table on another page.
I have currently got the following code:
PAGE NAME: EMBELLISHMENT
<script>
var embellishmentlist_var = embellishment;
var embellishment_explode = embellishmentlist_var.split("#");
for(var i = 1; i < embellishment_explode.length; i++)
{
var embellishment_explode_singleinfo = embellishment_explode.split("_");
//var table = '<tr><td>' + embellishment_explode[3] + '</td><td>' + data[7] + '</td><td>' + data[1] + '</td><td>' + data[2] + '</td><td>' + data[4] + '</td><td>' + data[5] + '</td>' + data1 + '<td>' + data[9] + '</td></tr>';
var table = '<tr><td></td></tr>';
$('#tableshow > tr').append( table );
//alert(embellishment_explode[4]);
}
}
</script>
<html>
<table>
<tr id="tableshow">
</tr>
</table>
The foreach can loop round a maximum of 6 times which I hope will create 6 rows within the table however this does not seem to be working. I currently have similar code to the above on another page however the HTML is slightly different. On that page the HTML looks like the following:
PAGE NAME: INFO
<table id="items_table">
<th>1</th>
<th>2</th>
///etc
</table>
The Javascript on that page insert rows into the table. This all works.
Therefore the only difference between the two pages is that on the EMBELLISHMENT page I want to create table rows within a table whereas on the INFO page I am creating the complete table.
Could I please have some assistance even if it is just to say it isn't possible.
You're trying to append table rows to a table row. That's not possible. You could only add rows to a table
HTML
<table id="tableshow"></table>
JS
for(var i = 0; i <= 6; i++){
$('#tableshow').append('<tr><td></td></tr>');
}
I am trying to create a HTML table like the following dynamically using jQuery:
<table id='providersFormElementsTable'>
<tr>
<td>Nickname</td>
<td><input type="text" id="nickname" name="nickname"></td>
</tr>
<tr>
<td>CA Number</td>
<td><input type="text" id="account" name="account"></td>
</tr>
</table>
This is my actual table :
<table border="0" cellpadding="0" width="100%" id='providersFormElementsTable'> </table>
This is the method which will create tr and td elements taking id and labelText:
function createFormElement(id, labelText) {
// create a new textInputBox button using supplied parameters
var textInputBox = $('<input />').attr({
type: "text", id: id, name: id
});
// create a new textInputBox using supplied parameters
var inputTypeLable = $('<label />').append(textInputBox).append(labelText);
// append the new radio button and label
$('#providersFormElementsTable').append(inputTypeLable).append('<br />');
}
I also have a value which will be shown as tool tip.
Please help me to create a table dynamically with tool tip and tr td.
EDIT:
I have almost done with the following code:
function createProviderFormFields(id, labelText,tooltip,regex) {
var tr = '<tr>' ;
// create a new textInputBox
var textInputBox = $('<input />').attr({
type: "text",
id: id, name: id,
title: tooltip
});
// create a new Label Text
tr += '<td>' + labelText + '</td>';
tr += '<td>' + textInputBox + '</td>';
tr +='</tr>';
return tr;
}
Here label is coming properly and the input box is not coming and it shows [object Object] where the text box has to come...
When I printed the textInputBox using console.log, I get the following:
[input#nickname, constructor: function, init: function, selector: "", jquery: "1.7.2", size: function…]
What could be the issue?
Thanks to #theghostofc who showed me path... :)
You may use two options:
createElement
InnerHTML
Create Element is the fastest way (check here.):
$(document.createElement('table'));
InnerHTML is another popular approach:
$("#foo").append("<div>hello world</div>"); // Check similar for table too.
Check a real example on How to create a new table with rows using jQuery and wrap it inside div.
There may be other approaches as well. Please use this as a starting point and not as a copy-paste solution.
Edit:
Check Dynamic creation of table with DOM
Edit 2:
IMHO, you are mixing object and inner HTML. Let's try with a pure inner html approach:
function createProviderFormFields(id, labelText, tooltip, regex) {
var tr = '<tr>' ;
// create a new textInputBox
var textInputBox = '<input type="text" id="' + id + '" name="' + id + '" title="' + tooltip + '" />';
// create a new Label Text
tr += '<td>' + labelText + '</td>';
tr += '<td>' + textInputBox + '</td>';
tr +='</tr>';
return tr;
}
An example with a little less stringified html:
var container = $('#my-container'),
table = $('<table>');
users.forEach(function(user) {
var tr = $('<tr>');
['ID', 'Name', 'Address'].forEach(function(attr) {
tr.append('<td>' + user[attr] + '</td>');
});
table.append(tr);
});
container.append(table);
Here is a full example of what you are looking for:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
$( document ).ready(function() {
$("#providersFormElementsTable").html("<tr><td>Nickname</td><td><input type='text' id='nickname' name='nickname'></td></tr><tr><td>CA Number</td><td><input type='text' id='account' name='account'></td></tr>");
});
</script>
</head>
<body>
<table border="0" cellpadding="0" width="100%" id='providersFormElementsTable'> </table>
</body>
I understand you want to create stuff dynamically. That does not mean you have to actually construct DOM elements to do it. You can just make use of html to achieve what you want .
Look at the code below :
HTML:
<table border="0" cellpadding="0" width="100%" id='providersFormElementsTable'></table>
JS :
createFormElement("Nickname","nickname")
function createFormElement(labelText, id) {
$("#providersFormElementsTable").html("<tr><td>Nickname</td><td><input type='text' id='"+id+"' name='nickname'></td><lable id='"+labelText+"'></lable></td></tr>");
$('#providersFormElementsTable').append('<br />');
}
This one does what you want dynamically, it just needs the id and labelText to make it work, which actually must be the only dynamic variables as only they will be changing. Your DOM structure will always remain the same .
WORKING DEMO:
Moreover, when you use the process you mentioned in your post you get only [object Object]. That is because when you call createProviderFormFields , it is a function call and hence it's returning an object for you. You will not be seeing the text box as it needs to be added . For that you need to strip individual content form the object, then construct the html from it.
It's much easier to construct just the html and change the id s of the label and input according to your needs.
FOR EXAMPLE YOU HAVE RECIEVED JASON DATA FROM SERVER.
var obj = JSON.parse(msg);
var tableString ="<table id='tbla'>";
tableString +="<th><td>Name<td>City<td>Birthday</th>";
for (var i=0; i<obj.length; i++){
//alert(obj[i].name);
tableString +=gg_stringformat("<tr><td>{0}<td>{1}<td>{2}</tr>",obj[i].name, obj[i].age, obj[i].birthday);
}
tableString +="</table>";
alert(tableString);
$('#divb').html(tableString);
HERE IS THE CODE FOR gg_stringformat
function gg_stringformat() {
var argcount = arguments.length,
string,
i;
if (!argcount) {
return "";
}
if (argcount === 1) {
return arguments[0];
}
string = arguments[0];
for (i = 1; i < argcount; i++) {
string = string.replace(new RegExp('\\{' + (i - 1) + '}', 'gi'), arguments[i]);
}
return string;
}