How to pass Object as parameter to a function onclick - javascript

I am facing some issues while trying to pass JSON object as a parameter to function!
but on that function, while consoling log the data I am getting [object:object].
Here is my code:
function buildTable(data) {
var table = document.getElementById("myTable");
table.innerHTML = "";
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 id="audio_handle" class="btn btn-primary" onclick="handleMembers('${data[i]}')">Video</button></td>`;
table.innerHTML += row;
}
}
function handleMembers(data) {
console.log("data = >", data); //= [object:object]
}
The issue is when I am calling handle function from the button inside template literal string I m getting [object:object] as output
Where I am going wrong?

I fixed a few points in the following snippet and added some HTML and some sample data:
// some sample data for illustration:
const data=[{id:1,name:"Harry",audio_muted:1,video_muted:1},{id:2,name:"Ron",audio_muted:1,video_muted:0},{id:3,name:"Hermiony",audio_muted:0,video_muted:1},{id:4,name:"Ginny",audio_muted:0,video_muted:1}];
const tbl=document.getElementById("myTable");
tbl.innerHTML = data.map((itm,i)=>`<tr class="item-id-${itm.id}"> <td>${itm.name}</td> <td>${itm.audio_muted}</td> <td>${itm.video_muted}</td> <td><button data-id="${i}" class="btn btn-primary">Video</button></td>`).join("\n")
tbl.addEventListener("click",ev=>{
if (ev.target.tagName==="BUTTON")
console.log("data = >", data[ev.target.dataset.id]) ; //= [object:object]
})
<table id="myTable"></table>
As #Quentin already mentioned you should not include JavaScript code within a template string. This gets too complicated to read and to maintain. Instead I used a delegated event-handler on the table itself to listen for the click on the button elements. By doing all this there was no need anymore for the two named functions.
Another thing that comes to my mind is: Never use element.innerHTML += ... inside a for loop as this will potentially become really slow. It is generally better to assemble the whole HTML string in one go and then assign it to the innerHTML property.

I think it's the wrong approach to do that. You should try to create the element using the DOM api and add the eventListener to the selected element, something like:
function buildTable(data) {
const table = document.getElementById("myTable");
for(let d of data) {
const tr = document.createElement("tr");
const td1 = document.createElement("td");
td1.textContent = d.name;
const td2 = document.createElement("td");
td2.textContext = d.audio_muted;
const td3 = document.createElement("td");
td3.textContent = d.video_muted;
const tdButton = document.createElement("button");
tdButton.classList.add("btn", "btn-primary");
tdButton.addEventListener("click", () => handleMembers(d));
tr.appendChild(td1)
tr.appendChild(td2)
tr.appendChild(td3)
tr.appendChild(tdButton);
table.appendChild(tr)
}
}

Related

Adding Filters to a Dynamically Generated HTML Table

I'm currently trying to add column-level filtering to an HTML table, generated from a click event listener, using the TableFilter JavaScript library, however I'm receiving the following error in the console:
Error: Could not instantiate TableFilter: HTML table requires at least 1 row.
The code I'm using to generate the table is below; in essence I'm taking in an array of objects, then looping through them to create a header row, then data rows and then appending the table to a <div>. The table itself renders without issue, but I'm unable to attach filters - could anyone shed any light on why this error is occurring? I'd suspected it might be something to do with trying to add a filter to the table before the element had been rendered, but I couldn't see why that would be the case. I'm aware that the documentation for the library recommends adding a <script> tag under the table, and I've also tried this however I'm not sure how to do that correctly since the table doesn't exist until the click event takes place (hence adding it to the onclick function).
HTML
<html>
<head>
<script src="script.js"></script>
<script src="/TableFilter/dist/tablefilter/tablefilter.js"></script>
</head>
<body>
<button id="my-button">Create Table</button>
<div id="my-table-container">
<!-- table -->
</div>
<script>
button = document.getElementById('my-button');
button.addEventListener('click', renderTable);
</script>
</body>
</html>
JavaScript
const createTableFromObjectArray = (data, containerRef, tableRef) => {
// elements
let container = document.getElementById(containerRef);
let table = document.createElement('table');
table.setAttribute('id', tableRef);
// clear the DOM if the table is already present
while (container.firstChild) {
container.removeChild(container.firstChild);
}
// create header
let headerRow = document.createElement('tr');
const colNames = Object.keys(data[0]);
colNames.forEach(name => {
let headerCell = document.createElement('th');
let headerText = document.createTextNode(name);
headerCell.appendChild(headerText);
headerRow.append(headerCell);
});
table.appendChild(headerRow);
// add rows to table
data.forEach(doc => {
let tableRow = document.createElement('tr');
Object.values(doc).forEach(value => {
let rowCell = document.createElement('td');
let cellText = document.createTextNode(value);
rowCell.appendChild(cellText);
tableRow.appendChild(rowCell);
});
table.appendChild(tableRow);
});
// add table to DOM and add filters
container.appendChild(table);
let tf = new TableFilter(table, {
base_path: '/TableFilter/dist/tablefilter/'
});
tf.init();
}
const renderTable = () => {
const data = [{'Name': 'John', 'Eyes': 'Blue', 'Hair': 'Brown'}];
const containerRef = 'my-table-container';
const tableRef = 'my-table';
createTableFromObjectArray(data, containerRef, tableRef);
}

Show a table (number of rows variable) on a div after click button? Works until some point

(This is my first question here and I am new to programming)
I am stuck on a problem and I tried to take something from here:
http://jsfiddle.net/4pEJB/
Dynamically generated table - using an array to fill in TD values
The function I created receive two vectors and creates a table with 2 columns, one for each vector, and lines = vector.length.
The function works fine, it seems to create the table as I need, but it doesn't show the table created on the browser screen after button click. By using some 'alert()' on the for loops I was able to verify that it uses the correct data.
In fact, when the button is clicked, it calls another function that processes some data and passes two vectors on this function I am showing here, but this part works well.
Here is the HTML part:
<div class="tableDiv">
<input type="button" onclick="createtable([1,3,5,7,9],[2,4,6,8,10])" value="Show data">
</div>
And here is the JavaScript part:
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
tableDiv.appendChild(table);
}
When the function finishes the table feed, it stops on tableDiv.appendChild(table);
Any advice or suggestions will be greatly appreciated! (I speak portuguese, I am sorry for some errors)
EDIT: it's possible to avoid the increment on the number of table rows that occurs every time we click the button (the solution provided generates one new table under the previous table). To solve this, I just added this line on the beggining of the function code (need to put the button outside the div and let the div empty, otherwise it will hide the button):
document.getElementById("tableDiv").innerHTML = "";
you are capturing by id, but you set up a class.chang it to id
<div id="tableDiv">
and append the tableBody into table.You're populating the table body with rows, but never appended the body into the table element.
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
table.appendChild(tableBody) // append tableBody into the table element
tableDiv.appendChild(table);
}
<div id="tableDiv">
<input type="button" onclick="createtable([1,3,5,7,9],[2,4,6,8,10])" value="Show data">
</div>
You try to append the var table to the tableDiv but the var table is stil empty.
Before append the tableBody to the var table and it will work.
Use id instead of class in your HTML Markup
<div id="tableDiv">
and then use the following code.
function createtable(vet_1,vet_2){
var tableDiv = document.getElementById("tableDiv");
var table = document.createElement("table");
var tableBody = document.createElement('tbody');
for (var r=0;r<vet_1.length;r++){
var row = document.createElement("tr");
for (var c=0;c<2;c++){
var cell = document.createElement("td");
if (c==0){cell.appendChild(document.createTextNode(vet_1[r]));}
else if(c==1){cell.appendChild(document.createTextNode(vet_2[r]));}
row.appendChild(cell);
}
tableBody.appendChild(row);
}
table.appendChild(tableBody);
tableDiv.appendChild(table);
}
First you are accessing the div using id whereas the node is defined with a class.
Secondly, you have to append the body to the table node first, and then append the table to the div selected.
Try this code snippet to move on.

JS Created buttons are not defined when accessed later

I have a script that makes a button in a table every 5 seconds.
I originally had the button made with the onclick attribute which called a function in the script. This however, gave me an error saying that the function didn't exist, and as from what I've seen on here, it has been answered but I don't know how I'd fix it in my situation. I switched it so that Javascript handles for the button click. I added attributes to the button tag to grab when the btnTeamListAction function is called. The console prints the following,
control.js:86 Uncaught TypeError: Cannot set property 'onclick' of null
at window.onload (control.js:86)
JS Snippets:
#button click handler
btnTeamListAction.onclick = function(){
var id = this.getAttribute("data-team-id");
var isRedo = this.getAttribute("data-is-redo");
teamListSelect(id,isRedo);
}
#the function that creates the buttons
function appendTeamTable(id,name,finished){
var finished_txt;
var action_content;
if(finished == 1){
finished_txt = "Yes";
action_content = '<button id="teams-list-action" data-team-id="'+id+'" data-is-redo="1">Retime</button>';
}
else {
finished_txt = "No";
action_content = '<button id="teams-list-action" data-team-id="'+id+'" data-is-redo="0">Time</button>';
}
var tr = document.createElement('tr');
tr.innerHTML ='<td>'+ id +'</td><td>'+ name +'</td><td>'+ finished_txt +'</td><td>'+ action_content +'</td>'
teamTable.appendChild(tr);
var btnTeamListAction = document.getElementById("teams-list-action");
btnTeamListAction.onclick = function(){
console.log("ActionClicked");
var id = this.getAttribute("data-team-id");
var isRedo = this.getAttribute("data-is-redo");
teamListSelect(id,isRedo);
}
}
I've tried browsing this form for this error and have found many related questions but not for this particular case with the button being created by JS itself.
Please ask if you need the full script or HTML, Thanks!
function appendTeamTable(id,name,finished){
var finished_txt;
var action_content= document.createElement("a");
var btn = document.createElement("button");
btn.setAttribute("id","teams-list-action");
btn.setAttribute("data-team-id",id);
if(finished == 1){
finished_txt = "Yes";
var t = document.createTextNode("Retime");
btn.setAttribute("data-is-redo","1");
}
else {
finished_txt = "No";
var t = document.createTextNode("Time");
btn.setAttribute("data-is-redo","0");
}
btn.appendChild(t);
btn.addEventListener("click",function(){
var id = this.getAttribute("data-team-id");
var isRedo = this.getAttribute("data-is-redo");
teamListSelect(id,isRedo);
});
action_content.appendChild(btn);
var tr = document.createElement('tr');
var td = document.createElement('td');
td.appendChild(action_content);
tr.innerHTML ='<td>'+ id +'</td><td>'+ name +'</td><td>'+ finished_txt +'</td>'
tr.appendChild(td);
teamTable.appendChild(tr);}
I looked at the post here and took the idea from the second answer and put a event handler on the table itself instead of the buttons individually. It's works like a charm now. Thanks all three of you for attempting to look through my seriously messed up code! :)

Cannot call method appendChild of null

It occurs in this:
for(var i = 0; i<phoneNums.length; i++)
{
var lines = document.createElement('tr');
var number = document.createElement('td');
number.innerHTML = phoneNums[i];
var minutes = document.createElement('td');
minutes.innerHTML = minutesUsed[i];
var plan = document.createElement('td');
plan.innerHTML = plans[i];
var charges = document.createElement('td');
charges.innerHTML = charge[i];
document.getElementById('theTable').appendChild(lines);
lines.appendChild(number);
lines.appendChild(minutes);
lines.appendChild(plan);
lines.appendChild(charges);
}
Specifically at:
document.getElementById('theTable').appendChild(lines);
<table id = 'theTable'>
</table>
<script type = 'text/javascript'>
populateTable();
</script>
I'm trying to create a function that adds tr and td and the values to a table.
You probably are running this script before "theTable" exists in your document. Make sure that this script occurs below your table with id="theTable", or that it is run in an event handler that occurs after the table exists.
This means that you do not have an element in your DOM with an id of "theTable". Somewhere in your html you should have something like:
<table id="theTable">...
Alternatively, as others have also mentioned, this element may not have been loaded into the DOM before your script executes.

Dynamcially added class works on <td> but not on <tr>. Why?

The function simply injects new rows into an empty table when the function is called.
it would seem that since the <td> class gets assigned properly, that the <tr> would also get assigned... but it doesn't!
var newRow = document.createElement("tr");
for (data in dataArray)
{
var newName = document.createElement("td");
newName.className = classNames[data];
newName.innerHTML = dataArray[data];
newRow.appendChild(newName);
counter++;
}
document.getElementById("capturedData").appendChild(newRow);
var newRow2 = document.createElement("tr");
newRow2.class = "hiddenRow";
for (data in dataArray)
{
var newData = document.createElement("td");
var newDataField = document.createElement("input");
newDataField.type = "hidden";
newDataField.name = "name" + data;
newDataField.value = dataArray[data];
newData.class = classNames[data];
newData.value = dataArray[data];
newData.appendChild(newDataField);
newRow2.appendChild(newData);
}
which is really weird. All the newly added <td> elements have their classes assigned and they show up in the DOM. But the <tr> elements don't accept the class assignment and in the DOM they have no class.
Why is this? I've read about the purported asynchronicity of script execution, but surely this can't be the case, it would defeat the purpose, no?
DOM elements have no property class, because it is a reserved keyword. You are looking for className:
newRow2.className = "hiddenRow";
Same for the cell (newData). It works for your other cell because you are using className already:
newName.className = classNames[data];
Use only className, not class . There is no class-property in <TR>.

Categories

Resources