I got a situation where I would like to read some data off a JSON format, however I am having some issues understanding how I should construct the button dynamically from JSON object.
My scenario is as follows:
$(document).ready(function() {
var socket = io.connect('http://' + document.domain + ':' + location.port);
// listen for mqtt_message events
// when a new message is received, log and append the data to the page
socket.on('mqtt_message', function(data) {
var json = JSON.parse(data['payload']);
var table = $("<table>");
table.append($("<tr><th>Host</th><th>Name</th><th>ID</th><th>"));
for (var i = 0; i < json.length; i++) {
var row = $("<tr><td>" + json[i]["name"] + json[i]["ID"] + "</td></tr>");
table.append(row);
}
table.appendTo($("#container"));
})
});
where
json = {"host":abc,"name":123,"id":345}
I have to make hostname as button and when I click on that button for example here, name "abc", i will get details name and id in table format. I have created table but it is showing whole table not that scenario which I actually want.
I am new to the JavaScript, facing issues here.
1) The JSON data doesn't seem to be an array, you can't loop through it.
2) You have to append the header to a <thead> element.
3) You have to append the table row to a <tbody> element.
All tables should have a <thead> and a <tbody> element, so just add it to your HTML code.
<div id="container">
<table style="display:none">
<thead>
<tr>
<th>Host</th>
<th>Name</th>
<th>ID</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
Then you append your data to these HTML elements, like so. If your data is an object and not an array, just don't loop through it but instead call the properties as is.
var json = [{
host: "Some host IP",
name: "Some name",
id: 345
},
{
host: "Some other host IP",
name: "Some other name",
id: 987
}
];
var $container = $("#container");
var $thead = $("#container table thead");
var $tbody = $("#container table tbody");
var $row = $("#container table tbody tr");
// Loop through items in JSON data..
json.forEach(function(item) {
var $button = $("<button>" + item.host + "</button>");
$container.prepend($button);
// Button click handler..
$button.on("click", function() {
// Replace row HTML..
$row.html('<td>' + item.host + '</td>' + '<td>' + item.name + '</td>' + '<td>' + item.id + '</td>');
// Show table if it's not already visible..
$("#container table").show();
});
});
Full code here:
https://jsfiddle.net/amsv/15h74uy6/
Vanilla JS, ie. without jQuery:
https://jsfiddle.net/amsv/15h74uy6/72/
let json = [
{"host":abc,"name":123,"id":345},
{"host":def,"name":456,"id":345}
]
In your html write
<button *ngFor = 'let item of json' (click)='buttonOnClick($event)'>
{{item.host}}
</button>
Above code will render two buttons for each element in the array
In your ts write
buttonOnClick(event) {
console.log(event) // you will get the corresponding object from the array
}
var sampleData = [{ "host": "abc", "name": 123, "id": 345 }, { "host": "xyz", "name": 456, "id": 678 }]
When data is received you should create button which shows table and set data attribute of button with received data.
for (var i = 0; i < sampleData.length; i++) {
var item = sampleData[i];
var button = $('<button />');
button.text(item.host);
button.data('data', JSON.stringify(item))
button.on('click', function (e) {
e.preventDefault();
showTable(e);
});
$('#buttons').append(button);
}
showTable is like as below
function showTable(e) {
var json = JSON.parse($(e.target).data('data'));
var table = $("<table>");
table.append($("<tr><th>Host</th><th>Name</th><th>ID</th><th>"));
var row = $("<tr><td>" + json["host"] + "</td><td>" + json["name"] + "</td><td>" + json["id"] + "</td></tr>");
table.append(row);
$("#table").html(table);
}
Html is below:
<div id="container">
<div id="buttons">
</div>
<div id="table">
</div>
</div>
Related
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.
I have a website with a list of json objects arranged something like this:
[
{
"a": true or false,
"b": "information",
"c": "information",
"d": "information",
"e": "information"
},
...
]
The idea of this code is to print out all the objects on a table and have a checkbox which filters out the false objects out when needed. The site is supposed to just have the the table with unfiltered object on there, but after I added the checkbox event listener the full table list disappeared. When I check the checkbox I get the filtered objects and it keeps adding more and more of the same filtered content on the bottom of the table if I keep re-clicking it.
What am I doing wrong here? Here is the code I have:
var stuff = document.getElementById("stuff-info");
var ourRequest = new XMLHttpRequest();
ourRequest.open('GET', 'url');
ourRequest.onload = function() {
var ourData = JSON.parse(ourRequest.responseText);
renderHTML(ourData);
};
ourRequest.send();
function renderHTML(data) {
var htmlString = "";
var filteredData = data.filter(function(element) {
return element.a
});
var checkbox = document.querySelector("input[name=hide]");
checkbox.addEventListener('change', function() {
if (this.checked) {
for (i = 0; i < filteredData.length; i++) {
htmlString += "<table><tr><td>" + filteredData[i].b + "</td><td>" + filteredData[i].c + "</td><td>" + filteredData[i].d + "</td><td>" + filteredData[i].e + "</td></tr>"
}
} else {
for (i = 0; i < data.length; i++) {
htmlString += "<table><tr><td>" + data[i].b + "</td><td>" + data[i].c + "</td><td>" + data[i].d + "</td><td>" + data[i].e + "</td></tr>"
}
}
stuff.insertAdjacentHTML('beforeend', htmlString);
});
}
Might be easier to filter with CSS selector:
#filter:checked ~ table .filter { display: none }
<input type=checkbox id=filter> Filter
<table border=1>
<tr class=filter><td>1</td><td>a</td></tr>
<tr><td>2</td><td>b</td></tr>
<tr class=filter><td>3</td><td>c</td></tr>
<tr><td>4</td><td>d</td></tr>
</table>
after I added the checkbox event listener the full table list disappeared.
All of your logic for deciding what to render is trapped inside your onchange event, so nothing will be drawn until a checkbox is changed.
When I check the checkbox I get the filtered objects and it keeps adding more and more of the same filtered.
All of your html strings are generated with += against the original htmlString variable trapped in the closure. So yeah, it will just keep adding more and more rows. You are also inserting the udated strings into the dom without removing the old table(s), so this will be exponential growth.
I think there is a great case here for higher order functions instead of for loops, you can use the map array method to transform each item in the array into a string, instead of manually iterating. This is cleaner and more maintainable.
Notice that now that the rendering logic is not mixed together with the event logic, it would be much easier to reuse the render function with some different data or different events. It's also somewhat trivial to add more transformations or filters.
const ourRequest = new XMLHttpRequest();
ourRequest.onload = function() {
const ourData = JSON.parse(ourRequest.responseText);
initialRender(ourData);
};
ourRequest.open('GET', 'url');
ourRequest.send();
function filterAll() { return true; }
function filterA() { return element.a; }
function toRowString(item) {
return `
<tr>
<td>${item.a}</td>
<td>${item.b}</td>
<td>${item.c}</td>
<td>${item.d}</td>
<td>${item.e}</td>
</tr>`;
}
function renderTable(predicate, parentElement, data){
const rows = data
.filter(predicate)
.map(toRowString);
parentElement.innerHTML = `<table>${rows}</table>`;
}
function initialRender(data) {
const stuff = document.getElementById("stuff-info");
const checkbox = document.querySelector("input[name=hide]");
renderTable(filterAll, stuff, data);
checkbox.addEventListener('change', function(event) {
renderTable(
event.target.checked ? filterA : filterAll,
stuff,
data
);
}
}
Okay, so i am pulling data from a json file and at the same time i am putting them in to a table. I've managed to give every td item a dynamic id. However, that id is only accessible inside the html and when i try to use for a function it is either undefined or it is getting the length of every row but not the id.
<script type='text/javascript'>
var dynID;
$(function() {
var data = [];
$.getJSON( 'f-data.json', function(data) {
$.each(data.data, function(i, f) {
var tblRow = "<tr><th>" + '<td id = "editable'+this.id+'">' + f.Title+ "</td></th>";
dynID = $(this).find("td").attr("id");
tblRow += '<th colspan="2"><button type ="submit" class="edit" onclick="editButton(dynID)"></i></button>';
$(tblRow).appendTo(".screens tbody");
});
});
});
<script type='text/javascript'>
function editButton(id) {
alert(id);
}
JSON :
{ "data":[
{
"Title": "Screen 1",
"id": 1
},{
"Title": "Screen 2",
"id": 2
}
The above produces a button and when the button is pressed the result is undefined. The strange thing is that the id's are generated correctly (e.g. editable1, editable2, etc). I guess am not selecting the id correctly?
You are running into reference issues within the $.each loop. Within the loop, the reference to $(this) is a jQuery object made of the element of data array. It does not have any HTML. I believe you meant to treat/parse tblRow as jQuery object and extract the id from it. Doing this is bad for performance. your current code simply the output of the button is:
<button onclick="editButton(dynID)"></button>
This is because dynID is becoming a part of the string -- there is no concatenating happening here. Hence, the output becomes a reference to a variable named dynID in the global scope window.
I would rewrite that code as below.
$.each(data.data, function(i, f) {
var id = this.id, // use id accross the loop.
tblRow = "<tr><th>" + '<td id = "editable' + id +'">' + f.Name + "</td></th>";
tblRow += '<th colspan="2"><button type ="submit" class="edit" onclick="editButton("' + id + '")"></i></button>';
$(tblRow).appendTo(".screens tbody");
});
When the labels are clicked, i am showing dynamic data and this is working fine with table sorter. Clicking on the table headers is sorting the table rows.
The issue i am facing is, after clicking the label "One" and then clicking on label "Two", and trying to sort data from the second response, it stops working from here onwards.
This is my code:
$(document).on("click", ".candlespattern", function() {
var clicked = $(this).attr("id");
var datatoselect = '';
if (clicked === 'one') {
datatoselect = myjsonresponse1;
} else if (clicked === 'two') {
datatoselect = myjsonresponse2;
}
var html = "";
html += '<thead><th class="thheaders">Symbol</th><th class="thheaders">Date</th></thead><tbody>';
for (var e = 0; e < datatoselect.length; e++) {
html += "<tr><td>" + datatoselect[e].name + "</td><td>" + datatoselect[e].date_time + "</td></tr>"
}
$("#candletable").html(html);
$('#candletable').tablesorter({}).tablesorterPager({
container: $(".pager"),
size: 20
});
$("#candletable").trigger("update");
$("#pager").show();
});
Here is JSFiddle
Ok so after researching this particular plugin, I came across a useful example.
First of all, your problem is most likely that you are overwriting the thead of the table each time the item is clicked leading to the plugin to lose some references. Here's how I suggest you do it:
Since the thead is the same for both responses, there's no need to add it dynamically each time and we can just put it in the HTML:
<table id="candletable" class="table table-striped tablesorter">
<!-- add the table head and an empty tbody -->
<thead>
<th class="thheaders">Symbol</th>
<th class="thheaders">Date</th>
</thead>
<tbody>
</tbody>
</table>
Next thing is that we should initialize the tablesorter only once, and then just update the data:
$(document).ready(function() {
// initialize the table sorter on document.ready
$('#candletable').tablesorter({}).tablesorterPager({
container: $(".pager"),
size: 20
});
$("#pager").hide();
});
Finally, we remove the thead data and the initialization from the click handler and add the created table rows to tbody:
$(document).on("click", ".candlespattern", function() {
var clicked = $(this).attr("id");
var datatoselect = '';
if (clicked === 'one') {
datatoselect = myjsonresponse1;
} else if (clicked === 'two') {
datatoselect = myjsonresponse2;
}
// create the table rows from the response
var html = "";
for (var e = 0; e < datatoselect.length; e++) {
html += "<tr><td>" + datatoselect[e].name + "</td><td>" + datatoselect[e].date_time + "</td></tr>"
}
// add the rows to table body
$("#candletable tbody").html(html);
// update the table
$("#candletable").trigger("update");
// show it
$("#pager").show();
});
Here's a working FIDDLE
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;
}