I was trying to make table using JavaScript.
I have created a function makeTable to generate table data each time it is been called.
My Code -
<table class="table table-striped">
<tr>
<th>User Name</th>
<th>Audio</th>
<th>Video</th>
</tr>
<tbody id="myTable">
</tbody>
</table>
function onMemberListUpdate(members) {
console.log("member updated")
buildTable(members);
}
function buildTable(data){
console.log("build table function called", data);
var table = document.getElementById('myTable');
for(var i =0; i<data.length; i++){
var row = `<tr> <td>${data[i].name}</td> <td>${data[i].audio_muted}</td> <td>${data[i].video_muted}</td> <td><button class="btn btn-primary">Audio</button></td>`
table.innerHTML += row;
}
}
Issue that I am facing here is whenever member list updates and onMemberListUpdate function gets called it calls buildTable function that makes new row each time I don't want to create new row each time instead I want to update the existing table data. How can I achieve this thing please help
Consider marking each row with an attribute that you can use to find it later when you need to update it.
You can (for example) add class="item-id-${data[i].id}" to the tr (as below)
function buildTable(data){
console.log("build table function called", data);
var table = document.getElementById('myTable');
for(var i =0; i<data.length; i++){
var row = `<tr class="item-id-${data[i].id}"> <td>${data[i].name}</td> <td>${data[i].audio_muted}</td> <td>${data[i].video_muted}</td> <td><button class="btn btn-primary">Audio</button></td>`
table.innerHTML += row;
}
}
then you can call updateRow and in that function you can get the row by doing $(".item-id-123") and you can create new html that replaces it, so something like this:
function updateRow(data) {
$(`.item-id-${data.id}`).replaceWith(`
<tr class="item-id-${data.id}">
<td>${data.name}</td>
<td>${data.audio_muted}</td>
<td>${data.video_muted}</td>
<td><button class="btn btn-primary">Audio</button></td>
</tr>`);
}
Related
I am trying to insert another row into a table with footer.
Here is my code:
function submit(){
/* Some code here with declarations & value assignings*/
let tble = document.getElementById("tabl");
let newEl = document.createElement("tr");
newEl.innerHTML="<td>"+nowSr+"</td> <td>"+taskForm+"</td> <td>"+tagForm+"</td> <td>Rs. "+amountForm+"</td>";
tble.appendChild(newEl, tble.lastElementChild.previousSibling.lastElementChild);
}
My function gives me below result:
As you can see (IN INSPECT ELEMENTS WINDOW) the new row is inserted after the footer. How to add it properly
after the last row in the table?
Don't insert the element directly to the <table> element, but select the <tbody> instead.
You can do that like that:
function submit(){
let tble = document.getElementById("tabl");
let newEl = document.createElement("tr");
newEl.innerHTML="<td>"+nowSr+"</td> <td>"+taskForm+"</td> <td>"+tagForm+"</td> <td>Rs. "+amountForm+"</td>";
tble.querySelector('tbody').appendChild(newEl, tble.lastElementChild.previousSibling.lastElementChild);
}
But you shouldn't use innerHTML to create the row (it could create an XSS vulnerability), use innerText or textContent instead. But that means that you have to create the <td>s differently:
function submit(){
let tble = document.getElementById("tabl");
let newEl = document.createElement("tr");
appendTD(newEl, nowSr);
appendTD(newEl, taskForm);
appendTD(newEl, tagForm);
appendTD(newEl, "Rs. "+amountForm);
tble.querySelector('tbody').appendChild(newEl, tble.lastElementChild.previousSibling.lastElementChild);
}
function appendTD(tr, text){
const td = document.createElement('td')
td.innerText = text
tr.appendChild(td)
}
Try puhsing to the tbody intead of the table directly
function addTableRow(){
const tbody = document.querySelector('#myTable tbody')
const newRow = document.createElement('tr')
newRow.innerHTML = `<td>Foo</td><td>Bar</td>`
tbody.appendChild(newRow)
}
<table id="myTable">
<thead>
<tr>
<th>Helo</th>
<th>World</th>
</tr>
</thead>
<tbody>
<tr>
<td>Foo</td>
<td>bar</td>
</tr>
</tbody>
</table>
<button onclick="addTableRow()">Add row</button>
Basically, I am comparing the data in two sheets, so I want to show a dialog box with the data of two cells from two sheets and two buttons for the user to select which data cell is correct. Then I would like to loop through all the data that differed from one sheet to the other.
How can I show a dialog with the data, make the script wait for the button to be pressed and then go to the next item on the list?
This is the script that I have so far:
<script>
function myfunction() {
google.script.run.withSuccessHandler(qcComparison).qcGetData();
}
function qcComparison(sheetsData) {
var sheet1 = sheetsData["sheet1"];
var sheet2 = sheetsData["sheet2"];
var lastRow = sheet1.length;
var lastCol = sheet1[0].length
var headers = sheet1[0];
for (var row=1; row<=lastRow; row++) {
for (var col=0; col<lastCol; col++) {
// Do the comparison one cell at a time
var value1 = sheet1[row][col];
var value2 = sheet1[row][col];
if (value1 != value2) {
// Do something
}
}
}
}
document.addEventListener("DOMContentLoaded", myfunction());
</script>
And this is the HTML dialog that I wan to update with the data:
<table id="qc-table" class="qc-table">
<tr>
<td><button id="sheet-1" class="btn btn-primary btn-sm">Sheet 1</button></td>
<td class="profile-data"><p id="sheet-1-profile">Data from cell 1</p></td>
</tr>
<tr>
<td><button id="sheet-2" class="btn btn-secondary btn-sm">Sheet 2</button></td>
<td class="profile-data"><p id="sheet-2-profile">Data form cell 2</p></td>
</tr>
</table>
To display a dialog box when the values are not equal you can call an HTML service to create the HTML within Apps Script and then use getUi().showModalDialog.
EDIT: for loops aren't the best solution since they will continue to execute while the dialog box is open. It is better to use recursion in this case.
Sample code below:
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var range1 = sheet1.getRange(1,1,sheet1.getLastRow(),sheet1.getLastColumn()).getValues();
var range2 = sheet2.getRange(1,1,sheet2.getLastRow(),sheet2.getLastColumn()).getValues();
function qcComparison() {
var row = 0, col = 0;
compare(row, col);
}
function compare(row, col) {
Logger.log(row, col);
if (range1[row][col] != range2[row][col]) {
Logger.log("Different values!");
var html = HtmlService.createTemplateFromFile("page");
html.row = row;
html.col = col;
html.cell1 = range1[row][col];
html.cell2 = range2[row][col];
var htmlOutput = html.evaluate();
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Choice');
}
else {
compareNext(row, col);
}
}
function compareNext(row, col) {
Logger.log("Compare next", row, col);
if (col < range1[row].length) {
if (row < range1[col].length-1) {
compare(++row, col);
}
else {
row = 0;
compare(row, ++col);
}
}
return;
}
The HTML is changed to accept values from Apps Script, sample code below:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<table id="qc-table" class="qc-table">
<tr>
<td>
<button id="sheet-1" class="btn btn-primary btn-sm" onclick="google.script.run.setSheet1(<?=row?>,<?=col?>,<?=cell1?>);google.script.host.close();">Sheet 1</button></td>
<td class="profile-data"><p id="sheet-1-profile">Data from Sheet 1: <?=cell1?> </p></td>
</tr>
<tr>
<td><button id="sheet-2" class="btn btn-secondary btn-sm" onclick="google.script.run.setSheet2(<?=row?>,<?=col?>,<?=cell2?>);google.script.host.close();">Sheet 2</button></td>
<td class="profile-data"><p id="sheet-2-profile">Data from Sheet 2: <?=cell2?> </p></td>
</tr>
</table>
</body>
</html>
Note that the script now runs functions upon click of Sheet 1 or Sheet 2 to update the values:
function setSheet1(row, col, value) {
sheet2.getRange(++row,++col).setValue(value);
compareNext(--row, --col);
}
function setSheet2(row, col, value) {
sheet1.getRange(++row,++col).setValue(value);
compareNext(--row, --col);
}
References:
showModalDialog()
Templated HTML
Communication between HTML and Apps Script
I have learnt a sample code from youtube on putting an array in HTML table dynamically that is sortable. Below is the code.
How do I made each record in display HTML table clickable and call a myFunction()? The myFunction() will then get the value of the Name in the respective row and execute another query.
HTML Part ->
<table class="table table-striped">
<tr class="bg-info">
<th data-column="name" data-order="desc">Name ▲</th>
<th data-column="age" data-order="desc">Age ▲</th>
<th data-column="birthdate" data-order="desc">Birthday ▲</th>
</tr>
<tbody id="myTable">
</tbody>
the javascript part
var myArray = [
{'name':'Michael', 'age':'30', 'birthdate':'11/10/1989'},
{'name':'Mila', 'age':'32', 'birthdate':'10/1/1989'},
{'name':'Paul', 'age':'29', 'birthdate':'10/14/1990'},
{'name':'Dennis', 'age':'25', 'birthdate':'11/29/1993'},
{'name':'Tim', 'age':'27', 'birthdate':'3/12/1991'},
{'name':'Erik', 'age':'24', 'birthdate':'10/31/1995'},
]
$('th').on('click', function(){
var column = $(this).data('column')
var order = $(this).data('order')
var text = $(this).html()
text = text.substring(0, text.length - 1)
if(order == 'desc'){
$(this).data('order', "asc")
myArray = myArray.sort((a,b) => a[column] > b[column] ? 1 : -1)
text += '▼'
}else{
$(this).data('order', "desc")
myArray = myArray.sort((a,b) => a[column] < b[column] ? 1 : -1)
text += '▲'
}
$(this).html(text)
buildTable(myArray)
})
buildTable(myArray)
function buildTable(data){
var table = document.getElementById('myTable')
table.innerHTML = ''
for (var i = 0; i < data.length; i++){
var row = `<tr>
<td>${data[i].name}</td>
<td>${data[i].age}</td>
<td>${data[i].birthdate}</td>
</tr>`
table.innerHTML += row
}
}
My Function Call Js part
function myFunction() { " wanna get the value of the row if link is click" }
You need to add the following after you call the buildTable(myArray) so the <tr> tags can render before you assign them a click event.
$('tr').click(function(){
var name = $(this).children('td').first().html();
yourFunction(name);
});
function yourFunction(name){
//do things with name here
}
Also, this assumes that the first td will always contain the name. A better implementation would be to refactor the buildTable function and give classes to your td
$(document).on("click", "tbody tr", function(){
//if you want name field
$(this).find("td:nth-child(1)").text();
//if you want age field
$(this).find("td:nth-child(2)").text();
});
i done the myFunction in Jquery, use this code inside your script tag
I am using a JavaScript snippet to show a responsive table, setting the headers on mobile via attributes. This works, but, if I use a second table with the same class, it goes all wrong on mobile (please resize your screen to see this); the headers of.
What am I doing wrong here and how can I fix this?
This is the HTML:
<table class="test">
<thead>
<tr>
<th>Bla</th>
<th>Bla</th>
<th>Bla</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bla</td>
<td>Blabla</td>
<td>Blablabla</td>
</tr>
</tbody>
</table>
<table class="test">
<thead>
<tr>
<th>Not</th>
<th>Not</th>
</tr>
</thead>
<tbody>
<tr>
<td>Twatwa</td>
<td>Twatwa</td>
</tr>
</tbody>
</table>
http://codepen.io/anon/pen/QbJqVv
Edit: after the new answer, it does show table headers on the second table now, but not the correct ones. It just puts the table headers of the first table, into the second.
As I wrote in the comments, you need to handle each table separately. For .querySelectorAll('.test th') will simply give you all th elements, irregardless of which table they belong to.
Here's a quick example of how this could be done.
// for each .test
[].forEach.call(document.querySelectorAll('.test'), function (table) {
// get header contents
var headers = [].map.call(table.querySelectorAll('th'), function (header) {
return header.textContent.replace(/\r?\n|\r/, '');
});
// for each row in tbody
[].forEach.call(table.querySelectorAll('tbody tr'), function (row) {
// for each cell
[].forEach.call(row.cells, function (cell, headerIndex) {
// apply the attribute
cell.setAttribute('data-th', headers[headerIndex]);
});
});
});
demo: http://codepen.io/anon/pen/NqEXqe
First of all, your HTML is invalid, as you are not closing any of your elements (<tr><td></td></tr> etc) - but that's another issue. Please practice good HTML standards.
You are not using querySelectorAll when selecting your table bodies, so you're only setting the attribute in the first one found.
This revised snippet should achieve what you are trying to do.
var headertext = [],
headers = document.querySelectorAll(".test th"),
tablerows = document.querySelectorAll(".test th"),
tablebody = document.querySelectorAll(".test tbody");
for(var i = 0; i < headers.length; i++) {
var current = headers[i];
headertext.push(current.textContent.replace(/\r?\n|\r/,""));
}
for (var tb = 0; tb < tablebody.length; tb++) {
for (var i = 0, row; row = tablebody[tb].rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
col.setAttribute("data-th", headertext[j]);
}
}
}
I am using Javascript to dynamically create a table, and want to make a header-style cell at the beginning of each row. So my question is how I can do this, seeing as insertCell creates only a normal <td> element and not a <th>.
Some things I've tried (via the Tryit editor at w3schools; I have no reason to suspect that any other usage will behave differently) and didn't work:
I've seen a suggestion to create the <th> element independently and then add it to the <tr> element as a child. When I do this, however, it is not added as a table cell, i.e. it is not affected by the table border, does not count toward the array of cells (i.e. if you do insertCell(1), it inserts after the first cell not counting the <th>), and does not get the special bold/center format for a <th> cell.
I've attempted to use insertCell to make a dummy cell and then replaceChild with an independently created cell; this had the same result as above.
I've tried to make a <td> cell via insertCell and simply bold and center it manually, but myCell.style.fontWeight="bold" and myCell.align="center" don't seem to work (they just end the function, as bad commands do in JavaScript), and likewise trying to use CSS doesn't work. So maybe I just have bad syntax or something, but I've got no clue what to do. Any help would be appreciated.
Attempt 1:
<!DOCTYPE html>
<html>
<body>
<p>Click the button to insert new cell(s) at the end of the table row.</p>
<table border="1">
<th>1</th>
<td>2</td>
</tr>
<tr id="myRow">
</tr>
<tr>
</table><br>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction()
{
var newRow = document.getElementById("myRow");
var header=document.createElement("th").appendChild(document.createTextNode("a"));
newRow.appendChild(header);
var enablesLoc=newRow.insertCell(0).appendChild(document.createTextNode("b"));
}
</script>
</body>
</html>
Result: "1" is bolded with a border, "2" and "b" are unbolded with a border (as they should be), "a" is unbolded with no border.
Attempt 2:
<!DOCTYPE html>
<html>
<body>
<p>Click the button to insert new cell(s) at the end of the table row.</p>
<table border="1">
<th>1</th>
<td>2</td>
</tr>
<tr id="myRow">
</tr>
<tr>
</table><br>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction()
{
var newRow = document.getElementById("myRow");
var header=newRow.insertCell(0).appendChild(document.createTextNode("a"));
header.style.fontWeight="bold";
var enablesLoc=newRow.insertCell(1).appendChild(document.createTextNode("b"));
}
</script>
</body>
</html>
Result: The button adds cell "a" unbolded but not cell "b".
The following code shows everything that should get you going:
function addTable(){
var table = document.createElement("table");
var tr = document.createElement("tr");
var th = document.createElement("th");
var td = document.createElement("td");
td.innerText = "im a td";
th.innerText = "im a th";
tr.appendChild(th);
tr.appendChild(td);
table.appendChild(tr);
var out = document.getElementById("out");
out.appendChild(table);
}
You have to call the function and an div with id out <div id=out>...</div> must be in the document. Disclaimer: i only tested this code in chrome
Update to address your points
You wrote I've seen a suggestion to create the <th> element independently and then add it to the <tr> element as a child. When I do this
it is not added as a table cell what do you mean by that and what command are you using,
is not affected by the table border the reason could be because it contains not text,
does not count toward the array of cells (i.e. if you do insertCell(1) i do not understand this either. According to the specs on insertCell it insert an empty td and returns a reference. So insertCell has no array, If you try var table = document.getElementById("myTable") and then table.rows[0].cells.length it returns the number of cells including the th-cell.
it inserts after the first cell not counting the th according on my tests at least in chrome this is not the case; it depends on how you call the method: table.rows[1].insertCell(-1); adds a cell at the second row (zero based array) at the end and table.rows[2].insertCell(1); adds in the third row a cell on position 2 (again zero based) if you use table.rows[3].insertCell(0); the cell is inserted into the 4th. row at the beginning,
and does not get the special bold/center format for a th cell this was not the case for me as well
Disclaimer: i only tested this code in chrome
The html
<button onclick="addRow()">add rows</button><br />
<button onclick="addColumn()">add column</button>
<table border="1" id="myTable">
<tr>
<th>1</th>
<td>2</td>
</tr>
</table>
And the javascript
function addRow()
{
var table = document.getElementById("myTable");
var tr = document.createElement("tr");
var th = document.createElement("th");
var td = document.createElement("td");
td.innerText = "im a td";
th.innerText = "im a th";
tr.appendChild(th);
tr.appendChild(td);
table.appendChild(tr);
}
function addColumn(){
var table = document.getElementById("myTable");
var rows = table.rows;
console.log("rows", rows);
for (var i = 0; i < rows.length; ++i) {
// td = rows[i].cells;
var td = document.createElement("td");
td.innerText = i;
rows[i].appendChild(td);
}
}
Based on DOM Level 2 HTML you can not use insertCell since it Insert[s] an empty TD cell into this row. But you want to add a th
According to DOM Level 3 Core you can use appendChild since it adds the node newChild to the end of the list of children of this node. If the newChild is already in the tree, it is first removed.
So therefore you have to create the elements in the right order: create the row, add the first cell as th then add other cells as td by using append child.
You may take a look at a demo of the above code
The .appendChild() method returns the element being appended. Which means on this line:
var header=document.createElement("th").appendChild(document.createTextNode("a"));
...your header variable is actually the text node, not the th element - so then newRow.appendChild(header); appends just the text node to the row, not the new th.
Try something like this instead:
var newRow = document.getElementById("myRow");
var header = document.createElement("th");
header.appendChild(document.createTextNode("a"));
newRow.appendChild(header);
Demo: http://jsfiddle.net/PtzRL/
Note that if you actually want to append new rows then your newRow variable should not be getting a reference to an existing row in the table, you should give an id to the table:
<table id="myTable">
...and then create a new row and add that to the table:
var table = document.getElementById("myTable");
var newRow = document.createElement("tr");
table.appendChild(newRow);
Demo: http://jsfiddle.net/PtzRL/1/
(Note also that the starting html you show has an error: you're missing the first <tr> just after the <table> tag, and you have an extra <tr> just before the closing </table> tag.)
Is this what you were trying to do?
function myFunction = function() {
var newRow, newHeader, newCell;
newRow = document.getElementById("myRow");
newHeader = document.createElement("th");
newHeader.innerText = "a";
newRow.appendChild(newHeader);
newCell = document.createElement("td");
newCell.innerText = "b";
newRow.appendChild(newCell);
}
If you want the button to add new rows rather than filling in a blank row you put there already, try something like this:
HTML:
<body>
<table id="myTable" border="1">
<tr>
<th>1</th>
<td>2</td>
</tr>
</table>
<button onclick="myFunction()">Try it</button>
</body>
JavaScript:
function myFunction = function() {
var myTable, newRow, newHeader, newCell;
myTable = document.getElementById("myTable");
newRow = document.createElement("tr");
newHeader = document.createElement("th");
newHeader.innerText = "a";
newRow.appendChild(newHeader);
newCell = document.createElement("td");
newCell.innerText = "b";
newRow.appendChild(newCell);
myTable.appendChild(newRow);
}
The function need to altered like this I believe...
function myFunction()
{
var newRow = document.getElementById("myRow");
var header=document.createElement("th");
header.appendChild(document.createTextNode("a"));
newRow.appendChild(header);
var enablesLoc=newRow.insertCell(0);
enables.appendChild(document.createTextNode("b"));
}