I have an HTML table and I want to iterate through its rows and create a collection or lets say an "array of objects".
For example:
<table id="tbPermission">
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td>1</td>
<td>Test1</td>
</tr>
</table>
I want to create a collection as below:
var trArray = [];
$('#tbPermission tr').each(function () {
var tdArray = [];
$(this).find('td').each(function () {
// I want to create the array of objects here …
tdArray.push();
});
// Final array
trArray.push(tdArray);
});
The arrays may be like below:
tdArray : {'UserID' : '1', 'UserName' : 'Test1'};
and:
trArray : [
{'UserID' : '1', 'UserName' : 'Test1'},
{'UserID' : '2', 'UserName' : 'Test2'}
]
Try this code
var trArray = [];
$('#tbPermission tr').each(function () {
var tr =$(this).text(); //get current tr's text
var tdArray = [];
$(this).find('td').each(function () {
var td = $(this).text(); //get current td's text
var items = {}; //create an empty object
items[tr] = td; // add elements to object
tdArray.push(items); //push the object to array
});
});
Here, I just created an empty object, filled object with references of tr and td, the added that object to the final array.
adding a working jsfiddle
This solution relies on adding thead and tbody elements which is a good idea anyways since it indicates to the browser that the table actually is a "data" table and not presentational.
jQuery has a .map() function. map is a basic function where you take an array and then replace the values with a the return value of a callback function - which results in a new array.
$([1,4,9]).map(function(){ return Math.sqrt(this) });
// [1, 2, 3]
.toArray converts the array like jQuery object we get into a "true array".
jQuery(function(){
var $table = $("#tbPermission");
var headers = $table.find('thead th').map(function(){
return $(this).text().replace(' ', '');
});
var rows = $table.find('tbody tr').map(function(){
var result = {};
var values = $(this).find('>td').map(function(){
return $(this).text();
});
// use the headers for keys and td values for values
for (var i = 0; i < headers.length; i++) {
result[headers[i]] = values[i];
}
// If you are using Underscore/Lodash you could replace this with
// return _.object(headers, values);
return result;
}).toArray();
// just for demo purposes
$('#test').text(JSON.stringify(rows));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="tbPermission">
<thead>
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Test1</td>
</tr>
</tbody>
</table>
<textarea id="test"></textarea>
If you for whatever reason cannot change the HTML you could use the index of the rows to differentiate between headers and rows of data:
var headers = $table.find('tr:eq(0) th').map(function(){
return $(this).text().replace(' ', '');
});
var rows = $table.find('tr:gt(0)').map(function(){
// ...
});
I would suggest changing your html slightly.
<table id="tbPermission">
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td class="userid">1</td>
<td class="username">Test1</td>
</tr>
</table>
Then in your javascript when you want to get all the elements as an array you could do.
var userIdArray = $('#tbPermission .userid').map(function(userid){ return $(userid).html(); }).toArray();
This will find all elements with a class userid on the table, collect just the values, and .toArray() that result to get a basic javascript array. You can then take that and manipulate it into whatever json structure you want, or you could possibly create your json object inside that map function.
Check the console, you will get an array with the desired objects
var arr = [];
$('#tbPermission tr:not(.header)').each(function() {
var that = $(this);
var id = that.find('td').eq(0).text();
var name = that.find('td').eq(1).text();
var obj = { 'userId': id , 'userName': name };
arr.push(obj);
});
console.log(arr);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table id="tbPermission">
<tr class="header">
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td>1</td>
<td>Test1</td>
</tr>
<tr>
<td>2</td>
<td>Test2</td>
</tr>
</table>
It's a bit tricky based on the given structure. You may have to modify the HTML a bit to map cells to headers, like below.
var myArray = [];
$("#tbPermission").find("td").each(function() {
var $this = $(this), obj = {};
obj[$this.data("column")] = $this.text();
myArray.push(obj);
});
alert ( JSON.stringify(myArray) );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="tbPermission">
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td data-column="User ID">1</td>
<td data-column="User Name">Test1</td>
</tr>
</table>
Please give in some time to learn about Array.push() and Objects in Javascript. Hope that helps.
Related
<table id="products" class="table table-dark table-hover" style="text-align: center;width:45%;margin: 4px">
<tr>
<th>Car</th>
<th>Model</th>
<th>Price</th>
<th>Basket</th>
</tr>
<tr onclick="buyProduct(this)">
<td>Mercedes_Benz</td>
</tr>
<tr onclick="buyProduct(this)">
<td>BMW</td>
</tr>
<tr onclick="buyProduct(this)">
<td>Toyota</td>
</tr>
</table>
<table id="basket" class="table table-dark table-hover" style="text-align: center;width:45%;margin: 4px"></table>
i have a problem with storing data to localstorage , i want to save clicked to localstorage and onload get it but on local storage it shows empty object, this is code,, Thank you in advance
var row = document.getElementsByTagName('tr');
var prod = document.getElementById('products');
var bas = document.getElementById('basket');
var k = 0;
var arr = [];
function buyProduct(x) {
arr[k] = x;
localStorage.setItem("sold"+k, JSON.stringify(arr))
x.remove();
x.removeAttribute('onclick')
bas.append(x);
k++;
}
window.onload = function() {
var stored;
if(localStorage) {
for(var i = 0; i < localStorage.length; i++) {
stored = localStorage.getItem("sold"+i);
console.log(JSON.parse(stored))
}
}
}
When you invoke onclick="buyProduct(this)" you're saving the DOM <tr> elements in the array, not their associated values.
The JSON.stringify() function finds no enumerable properties on those elements, and so saves an empty object.
If you actually want the contents of the <td> that's within the row you could use this:
arr.push(this.querySelector('td').textContent);
NB: note use of push to add to the end of the array instead of the error-prone practice of maintaining your own variable tracking the array's length.
I need to sort the first td elements of 3 tables. I must use jQuery to do it not pure javascript. Example:
<table>
<tr>
<td>cx</td>
<td>xx</td>
</tr>
</table>
<table>
<tr>
<td>bx</td>
<td>xx</td>
</tr>
</table>
<table>
<tr>
<td>ax</td>
<td>xx</td>
</tr>
</table>
The result I would like to get is:
<table>
<tr>
<td>ax</td>
<td>xx</td>
</tr>
</table>
<table>
<tr>
<td>bx</td>
<td>xx</td>
</tr>
</table>
<table>
<tr>
<td>cx</td>
<td>xx</td>
</tr>
</table>
Edit 1: that is what I'm trying to do: if you just could tell me how to get the current td element value it would be nice for me
Edit 2: Now The values in the result is the same as before sorting. Sorry for my mistake
var table = $("table");
var currentTableTd;
$.each(table, function(k, v) {
//currentTableTd = v.find("td:first-child");
//window.console.log(currentTableTd); // will log error v.find() is not a function which I understand because var v isn't a Jquery object.
//or
currentTableTd = $(this).find("td:first-child").text();
window.console.log(currentTableTd); //log undefined
})
you could use sort, then replace the html:-
var sorted = $('table').sort(function(a, b) {
return $('td:first', a).text().localeCompare($('td:first', b).text());
}).clone();
sorted.each(function(i, e) {
$('table').eq(i).html($(e).html());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>cx</td>
<td>xx</td>
</tr>
</table>
<table>
<tr>
<td>bx</td>
<td>xx</td>
</tr>
</table>
<table>
<tr>
<td>ax</td>
<td>xx</td>
</tr>
</table>
Finally after working on this problem during 24hours I have found my own solution. I post it here. Maybe it could helps other people.
Special thanks to those people who "voted down" on my question without helping me. They gave me the willpower to find my own solution.
var table = $("table");
$.each(table, function (k, v) {
var $currentTable = $("table").eq(k);
var $tr = $currentTable.find("tr").not(":first");
var $tdAll = $tr.find("td:first");
var textNodes = []; //collecting textNodes of td elements
var map = {}; //mapping $tdAll
var result = []; //contains sorted td elements to be added to the dom
$.each($tdAll, function (k, v) {
textNodes.push($(v).text());
map[k] = $(v);
})
textNodes.sort();
for (var i = 0; i < textNodes.length; i++) {
for (var key in map) {
if (textNodes[i] === $(map[key]).text())
result.push($(map[key]));
}
}
//Dom construction
$tr.find("td").remove();
for (var i = 0; i < textNodes.length; i++) {
$tr.eq(i).find("td:first").before($(result[i]));
}
})
I am trying to filter the rows of a table to display the results of entered text in the search bar. The code below does the job but for some reason filters the column headings as well.
$('#search').keyup(function () {
var data = this.value.split(" ");
var rows = $(".Info").find("tr").hide();
if(this.value ==""){
rows.show();
return;
}
rows.hide();
rows.filter(function(i,v){
var t = $(this);
for (var d = 0; d < data.length; d++) {
if (t.is(":Contains('" + data[d] + "')")) {
return true;
}
}
return false;
}).show();
});
HTML
<input type = "search" name = "search" id = "search">
<table style ="width:95%" class = "Info">
<tr>
<th>Select </th>
<th>Name</th>
<th>Number</th>
<th>Date</th>
</tr>
</table>
The user adds rows which is why i haven't written any HTML for it.
Any help would be appreciated. Thanks in advance
http://jsfiddle.net/szjhngwm/
It looks like you need to filter using tbody
<table style ="width:95%" class = "Info">
<thead>
<tr>
<th>Select </th>
<th>Name</th>
<th>Number</th>
<th>Date</th>
</tr>
<thead>
<tbody>
</tbody>
</table>
var rows = $(".Info tbody tr").hide();
Another way to do this would be to use jQuery's :gt() selector.
The only thing that would change is this line:
var rows = $(".Info").find("tr:gt(0)").hide();
Notice the addition of :gt(0) to your tr.
I'm not sure if I'm trying to do too much here, but here is the scenario. I have an asp.net mvc page that, on the first time loading, returns a table of data in a view using the standard foreach mechanisms in the mvc framework. If the user has javascript enabled, I want to use knockout to update the table going forward. Is there a way to have knockout read the data from the dom table and use that data as the initial observable collection. From then on out, I would use knockout and ajax to add, edit, or delete data.
In a nutshell, I need to parse an html table into a knockout observable collection.
I've had a go at coding this up:
Here's the basic markup:
<table id="table" data-bind="template: { name: 'table-template' }">
<thead>
<tr>
<th>Name</th>
<th>Surname</th>
</tr>
</thead>
<tbody>
<tr>
<td>Richard</td>
<td>Willis</td>
</tr>
<tr>
<td>John</td>
<td>Smith</td>
</tr>
</tbody>
</table>
<!-- Here is the template we'll use for re-building the table -->
<script type="text/html" id="table-template">
<thead>
<tr>
<th>Name</th>
<th>Surname</th>
</tr>
</thead>
<tbody data-bind="foreach: data">
<tr>
<td data-bind="text: name"></td>
<td data-bind="text: surname"></td>
</tr>
</tbody>
</script>
Javascript:
(function() {
function getTableData() {
// http://johndyer.name/html-table-to-json/
var table = document.getElementById('table');
var data = [];
var headers = [];
for (var i = 0; i < table.rows[0].cells.length; i++) {
headers[i] = table.rows[0].cells[i].innerHTML.toLowerCase().replace(/ /gi, '');
}
// go through cells
for (var i = 1; i < table.rows.length; i++) {
var tableRow = table.rows[i];
var rowData = {};
for (var j = 0; j < tableRow.cells.length; j++) {
rowData[headers[j]] = tableRow.cells[j].innerHTML;
}
data.push(rowData);
}
return data;
}
var Vm = function () {
this.data = ko.observableArray(getTableData());
};
ko.applyBindings(new Vm(), document.getElementById('table'));
})();
You can extend this concept using the mapping plugin to create observables for each row: http://knockoutjs.com/documentation/plugins-mapping.html
View a demo here: http://jsfiddle.net/CShqK/1/
EDIT: I'm not saying this is the best approach, as it can be costly to traverse a large table to get the data. I would probably just output the JSON in the page as suggested by others in this thread.
How about just feeding your observable array with the data instead of parsing the html table
myArray: ko.observableArray(#Html.Raw(Json.Encode(Model.myTableData)))
If you really need to go the parsing the html way, you can use the following code
var tableData = $('#myTable tr').map(function(){
return [
$('td,th',this).map(function(){
return $(this).text();
}).get()
];
}).get();
$(document).ready(function() {
var myData = JSON.stringify(tableData);
alert(myData)
});
Here is a fiddle showing the code in action:
http://jsfiddle.net/FWCXH/
Assuming I have the following table:
<table>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>A1</td>
<td><input type="checkbox"/> A2</td>
<td>A3</td>
</tr>
<tr>
<td>B1</td>
<td><input type="checkbox"/> B2</td>
<td>B3</td>
</tr>
<tr>
<td>C1</td>
<td><input type="checkbox"/> C2</td>
<td>C3</td>
</tr>
</tbody>
</table>
I want to generate JSON from the table only for the rows whose checkbox is checked. What do I put in for "Insert Check Here"?
var myRows = [];
var $headers = $("th");
var $rows = $("tbody tr").each(function(index) {
$cells = $(this).find("td");
myRows[index] = {};
$cells.each(function(cellIndex) {
// Insert Check Here
myRows[index][$($headers[cellIndex]).html()] = $(this).html();
});
});
var myObj = {};
myObj.myrows = myRows;
alert(JSON.stringify(myObj));
I've added an If statement to test if the TD contains a checkbox which is checked or not, see the comment in the code
// Loop through grabbing everything
var myRows = [];
var $headers = $("th");
var $rows = $("tbody tr").each(function(index) {
$cells = $(this).find("td");
myRows[index] = {};
$cells.each(function(cellIndex) {
if($(this).find('checkbox').is(':checked')) //Find the checkbox within the TD and test if it's checked or not
{
myRows[index][$($headers[cellIndex]).html()] = $(this).html();
}
});
});
// Let's put this in the object like you want and convert to JSON (Note: jQuery will also do this for you on the Ajax request)
var myObj = {};
myObj.myrows = myRows;
alert(JSON.stringify(myObj));
Try with:
var selectedRowsHTML = "";
$('table input:checked').each(function() {
selectedRowsHTML += $(this).closest('tr').html();
});
console.log("This is the HTML for selected rows: "+ selectedRowsHTML);
With ":checked" selector you get only inputs that are checked inside your table. Iterate over them, finding the parent row with "closest('tr')". And that's all, you get the HTML for every row (or whatever you want to do with them).
how about thus
$("table input:checked") //filter based on your requirement
.each(function()
{
var td=$(this).parent(); //gets the `td`, do the necessary
});
You can use the checkbox:checked selector and closest to find the nearest element of a specific type.
var selectedRows = [];
$('table input:checkbox:checked').each(function() {
selectedRows.push($(this).closest('tr'))
});
selectedRows contains an array of the selected table rows