HTML Table to JSON file via AJAX - javascript

Is there any possibility to convert an HTML table to JSON with PHP?
I have this JavaScript:
<script>
(function() {
var jsonArr = [];
var obj = {};
var rowIx = 0;
var jsonObj = {};
var thNum = document.getElementsByTagName('th').length;
var arrLength = document.getElementsByTagName('td').length;
for(i = 0; i < arrLength; i++){
if(i%thNum === 0){
obj = {};
}
var head = document.getElementsByTagName('th')[i%thNum].innerHTML;
var content = document.getElementsByTagName('td')[i].innerHTML;
obj[head] = content;
if(i%thNum === 0){
jsonObj[++rowIx] = obj
}
}
var result = "<br>"+JSON.stringify({"Values": jsonObj});
document.write(result);
})();
</script>
which uses the below HTML code:
<TABLE border="3" rules="all" bgcolor="#E7E7E7" cellpadding="1" cellspacing="1">
<TR>
<TH align=center><font size="3" face="Arial">Date</font></TH>
<TH align=center><font size="3" face="Arial"><B>Teacher</B></font></TH>
<TH align=center><font size="3" face="Arial">?</font></TH>
<TH align=center><font size="3" face="Arial">Hour</font></TH>
<TH align=center><font size="3" face="Arial">Subject</font></TH>
<TH align=center><font size="3" face="Arial">Class</font></TH>
<TH align=center><font size="3" face="Arial">Room</font></TH>
<TH align=center><font size="3" face="Arial">(Teacher)</font></TH>
<TH align=center><font size="3" face="Arial">(Room)</font></TH>
<TH align=center><font size="3" face="Arial">XYY</font></TH>
<TH align=center><font size="3" face="Arial"><B>Information</B></font></TH>
<TH align=center><font size="3" face="Arial">(Le.) nach</font></TH>
</TR>
<TR><TD align=center><font size="3" face="Arial">24.9.</font></TD>
<TD align=center><font size="3" face="Arial"><B><strike>Dohe</strike></B></font></TD>
<TD align=center><font size="3" face="Arial">Free</font></TD>
<TD align=center><font size="3" face="Arial">1</font></TD>
<TD align=center><font size="3" face="Arial"><strike>Math</strike></font> </TD>
<TD align=center><font size="3" face="Arial">(9)</font> </TD>
<TD align=center><font size="3" face="Arial">---</font> </TD>
<TD align=center><font size="3" face="Arial"><strike>Dohe</strike></font></TD>
<TD align=center><font size="3" face="Arial">A001</font></TD>
<TD align=center> </TD>
<TD align=center> </TD>
<TD align=center><font size="3" face="Arial">Free.</font></TD>
</TR>
</TABLE>
to generate this JSON code:
{"Values":{"1":{"Date":"24.9.","Teacher":"Dohe","?":"Free","Hour":"1","Subject":"Math ","Class":"(9) ","Room":"--- ","(Teacher)":"Dohe","(Room)":"A001","XYY":" ","Information":" ","(Le.) nach":"Free."},"2":{"Date":"26.9.","Teacher":"John","?":"Free","Hour":"8","Subject":"Bio ","Class":"(9) ","Room":"--- ","(Teacher)":"John","(Room)":"A021","XYY":" ","Information":" ","(Le.) nach":"Free."}}}
The script is perfect but I need a script, which saves the JSON data to a file on the server automatically, without any user interaction.

If you say your JS logic is perfect, here is a PHP (ver 5.3+) conversion that uses DOM like your code.
This function loads a html file (you may use curl if it is an url) then convert it and save to a file.
function save_table_to_json ( $in_file, $out_file ) {
$html = file_get_contents( $in_file );
file_put_contents( $out_file, convert_table_to_json( $html ) );
}
function convert_table_to_json ( $html ) {
$document = new DOMDocument();
$document->loadHTML( $html );
$obj = [];
$jsonObj = [];
$th = $document->getElementsByTagName('th');
$td = $document->getElementsByTagName('td');
$thNum = $th->length;
$arrLength = $td->length;
$rowIx = 0;
for ( $i = 0 ; $i < $arrLength ; $i++){
$head = $th->item( $i%$thNum )->textContent;
$content = $td->item( $i )->textContent;
$obj[ $head ] = $content;
if( ($i+1) % $thNum === 0){ // New row. Slightly modified to keep it correct.
$jsonObj[++$rowIx] = $obj;
$obj = [];
}
}
return json_encode([ "Values" => $jsonObj ]);
}
// Example
save_table_to_json( 'table.html', 'data.json' );

Personally, I like using JQuery, yet if you don't know or can't insert it as a SRC, then we should assume to use JavaScript. So we will post the JSON data to our PHP via AJAX when the page is done loading. The PHP will then write this JSON into a new file on the server called subs.json and will be overwritten each time the script runs.
We will start with the JavaScript:
<script>
function collectData() {
var jsonArr = [];
var obj = {};
var rowIx = 0;
var jsonObj = {};
var thNum = document.getElementsByTagName('th').length;
var arrLength = document.getElementsByTagName('td').length;
for(i = 0; i < arrLength; i++){
if(i%thNum === 0){
obj = {};
}
var head = document.getElementsByTagName('th')[i%thNum].innerHTML;
var content = document.getElementsByTagName('td')[i].innerHTML;
obj[head] = content;
if(i%thNum === 0){
jsonObj[++rowIx] = obj;
}
}
return jsonObj;
}
function postJSONData(json){
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "/subPost.php");
xmlhttp.setRequestHeader("Content-Type", "application/application/x-www-form-urlencoded");
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var return_data = xmlhttp.responseText;
alert(return_data);
}
}
xmlhttp.send("values="+JSON.stringify(json));
}
postJSONData(collectData());
</script>
At this point, the page should post your JSON to a PHP page called subPost.php located at the same level as the page that is executing this JS. This PHP Will look like:
<?php
if(isset($_POST['values'])){
$values = $_POST['values'];
$fp = fopen('subs.json', 'w');
fwrite($fp, $values);
fclose($fp);
echo "Values written to subs.json.\r\n";
} else {
echo "No Post data received.";
}
?>
I made a working example you can see here: http://www.yrmailfrom.me/projects/testPost/ and the content of http://www.yrmailfrom.me/projects/testPost/subs.json is:
{"1":{"<font face=\"Arial\" size=\"3\">Date</font>":"<font face=\"Arial\" size=\"3\">24.9.</font>","<font face=\"Arial\" size=\"3\"><b>Teacher</b></font>":"<font face=\"Arial\" size=\"3\"><b><strike>Dohe</strike></b></font>","<font face=\"Arial\" size=\"3\">?</font>":"<font face=\"Arial\" size=\"3\">Free</font>","<font face=\"Arial\" size=\"3\">Hour</font>":"<font face=\"Arial\" size=\"3\">1</font>","<font face=\"Arial\" size=\"3\">Subject</font>":"<font face=\"Arial\" size=\"3\"><strike>Math</strike></font> ","<font face=\"Arial\" size=\"3\">Class</font>":"<font face=\"Arial\" size=\"3\">(9)</font> ","<font face=\"Arial\" size=\"3\">Room</font>":"<font face=\"Arial\" size=\"3\">---</font> ","<font face=\"Arial\" size=\"3\">(Teacher)</font>":"<font face=\"Arial\" size=\"3\"><strike>Dohe</strike></font>","<font face=\"Arial\" size=\"3\">(Room)</font>":"<font face=\"Arial\" size=\"3\">A001</font>","<font face=\"Arial\" size=\"3\">XYY</font>":"
This is not valid JSON. It seems that some data is being misunderstood. I suspect that this is due to characters in the values, like . I see this in the posted data:
"<font face=\"Arial\" size=\"3\">XYY</font>":"
[nbsp;","<font_face] => \"Arial\" size=\"3\">(Le.) nach</font>":"<font face=\"Arial\" size=\"3\"
>Free.</font>"}}
I was able to overcome this with another small JS function:
function nbsp2space(str) {
return String(str).replace(/ /g, ' ');
}
Then use this function in collectData() like so:
obj[head] = nbsp2space(content);
Now when the page executes, we post the data to the PHP and it's written to the file subs.json.

You can try some thing like this:
HTML
<table>
<tr>
<th>No</th>
<th>Name</th>
<th>Email</th>
</tr>
<tr>
<td>1</td>
<td>Test</td>
<td>test#example.com</td>
</tr>
<tr>
<td>2</td>
<td>Test 2</td>
<td>test2#example.com</td>
</tr>
<tr>
<td>3</td>
<td>Test 3</td>
<td>test3#example.com</td>
</tr>
</table>
Javascript
<script type="text/javascript">
jQuery(document).ready(function(){
data = new Array();
columns = [];
var row = new Array();
$('table tr').each(function(index,tr){
var index = index;
if(index == 0){ // First we get column names from th.
$(tr).find('th').each(function(thIndex,thValue){
columns.push($(thValue).text());
});
} else {
$(tr).find('td').each(function(tdIndex,tdValue){
row[tdIndex] = $(tdValue).text(); // Put each td value in row
});
data.push(row); // now push each row in data.
row = new Array(); // reset row after push
}
});
// Send it to PHP for further work:
$.post('json.php', { data: data, columns: columns }, function(response){
// TODO with response
});
})
</script>
json.php
$data = $_POST['data']; // Each rows values
$columns = $_POST['columns']; // Columns names
for($i = 0; $i < count($data); $i++) {
$json[] = array(($i+1) => array_combine($columns, $data[$i]));
}
$json = json_encode($json);
// TODO with $json eg: file_put_contents();
the output you will get after json_encode() is:
{"values":[{"1":{"No":"1","Name":"Test","Email":"test#example.com"}},{"2":{"No":"2","Name":"Test 2","Email":"test2#example.com"}},{"3":{"No":"3","Name":"Test 3","Email":"test3#example.com"}}]}
Note jQuery must be included before running this.

Related

Export multiple html tables to PDF using jQuery tableHTMLExport plugin

I have multiple tables in my page and I want to export them into one pdf file.
I have tried this jQuery tableHTMLExport plugin https://www.jqueryscript.net/table/export-table-json-csv-txt-pdf.html. I have modified it but did not work well. It prints all the tables data except the heading for each table.
html file
<div id='print'>
<table>
<thead>
<tr>
<th>Career History</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td> <p> Job Title</p></td>
<td> <p> Company Name</p></td>
<td> <p> Start Date</p></td>
<td> <p> End Date</p></td>
</tr>
<?php foreach ($history as $h) { ?>
<tr>
<td>
<?php echo $h ['job_title']; ?>
</td>
<td>
<?php echo $h ['comapny_name']; ?>
</td>
<td>
<?php echo $h ['start_day']; ?>
</td>
<td>
<?php echo $h['end_day']; ?>
</td>
</tr>
<?php } ?>
</tbody>
</table>
<table class="table" id="3">
<thead>
<tr>
<th>Documents</th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>one</td>
<td>two</td>
<td>three</td>
<td>four</td>
</tr>
</tbody>
</table>
</div>
<input type='button' value='export pdf' id='save'/>
<script>
$("#save").click(function () {
$("#print").tableHTMLExport({
type: 'pdf',
filename: 'test.pdf' });
});
in the tableHTMLExport.js file I have add nested loop
function toJson(el) {
var i, j;
var jsonHeaderArray = [];
for (i = 0; i < 4; i++) {
$(el).find('thead').find('tr').not(options.ignoreRows).each(function () {
var tdData = "";
var jsonArrayTd = [];
$(this).find('th').not(options.ignoreColumns).each(function (index, data) {
if ($(this).css('display') !== 'none') {
jsonArrayTd.push(parseString($(this)));
}
});
jsonHeaderArray.push(jsonArrayTd);
});
for (j = 0; j < 4; j++) {
var jsonArray = [];
$(el).find('tbody').find('tr').not(options.ignoreRows).each(function () {
var tdData = "";
var jsonArrayTd = [];
$(this).find('td').not(options.ignoreColumns).each(function (index, data) {
if ($(this).css('display') !== 'none') {
jsonArrayTd.push(parseString($(this)));
}
});
jsonArray.push(jsonArrayTd);
});
}
return {header: jsonHeaderArray[i], data: jsonArray};
}
}
I have used available javaScript for exporting multiple tables and edited as my needs, you can attach this method to an input button
function generate() {
var doc = new jsPDF('p', 'pt');
var res1,res0;
var title = document.getElementById('title').value;
// first table
res0 = doc.autoTableHtmlToJson(document.getElementById('0'));
//get the columns & rows for first table
doc.autoTable(res0.columns, res0.data, {margin: {top: 80}});
// second table
res1 = doc.autoTableHtmlToJson(document.getElementById('1'));
// header for pdf file
var header = function (data) {
doc.setFontSize(18);
doc.setTextColor(40);
doc.setFontStyle('normal');
doc.text(title + " Profile", data.settings.margin.left, 50);
};
// setting up new option for the second table
var options = {
beforePageContent: header,
margin: {
top: 80
},
startY: doc.autoTableEndPosY() + 20
};
// add columns & rows for the second table
doc.autoTable(res1.columns, res1.data, options);
// save pdf file with the following name
doc.save("table.pdf");
}
if you have other solutions please share it.

Unable to store particular target values in jQuery

$(document).ready(e => {
$(".test").click(e => {
textvalue = displayData(e);
console.log(textvalue); //prints the array
});
});
function displayData(e) {
let i = 0;
const td = $("#tbody tr td");
let textvalues = [];
for (const value of td) {
if (value.dataset.name == e.target.dataset.name) {
textvalues[i++] = value.textContent;
}
}
return textvalues;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Gender</th>
<th>Email</th>
<th>Contact</th>
<th>Department</th>
<th>Edit</th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td>DummyName</td>
<td>20</td>
<td>Female</td>
<td>DummyEmail</td>
<td>DummyContact</td>
<td>DummyDepartment</td>
<td class="test">Click</td>
</tr>
<tr>
<td>DummyName2</td>
<td>22</td>
<td>Female</td>
<td>DummyEmail2</td>
<td>DummyContact2</td>
<td>DummyDepartment2</td>
<td class="test">Click</td>
</tr>
</tbody>
</table>
</body>
</html>
I'm using jQuery to update onscreen values in a form. Complete beginner at this.
$(document).ready(e =>{
$(".btnedit").click(e =>{
textvalues = displayData(e);
let sname = $("input[name*='name_type");
let sage = $("input[name*='age_type");
let sgender = $("input[name*='gender_type");
let semail = $("input[name*='email_type");
let scontact = $("input[name*='contact_type");
let sdept = $("input[name*='dept_type");
sname.val(textvalues[0]);
sage.val(textvalues[1]);
sgender.val(textvalues[2]);
semail.val(textvalues[3]);
scontact.val(textvalues[4]);
sdept.val(textvalues[5]);
});
});
function displayData(e){
let i = 0;
const td = $("#tbody tr td");
let textvalues = [];
for(const value of td){
if(value.dataset.name == e.target.dataset.name)
{
//console.log(value);
textvalues[i++] = value.textContent;
}
}
return textvalues;
}
I need to get the data stored in a table onto the inputs of the form, in order for the user to update it further. The user clicks on a record to edit it(which is displayed on the page).
The record values are stored in the array textvalues. Problem is the entire table values get stored in the array instead of just the single record.
In value.dataset.name, name is a column from the table which I'm using as the primary key (I know it's wrong, but just going with it for now).
Edit: Original table code:
while($row = mysqli_fetch_assoc($result))
{
?>
<tr>
<td data-name = "<?php echo $row['name']; ?>"><?php echo $row['name'];?></td>
<td data-name = "<?php echo $row['name']; ?>"><?php echo $row['age'];?></td>
<td data-name = "<?php echo $row['name']; ?>"><?php echo $row['gender'];?></td>
<td data-name = "<?php echo $row['name']; ?>"><?php echo $row['email'];?></td>
<td data-name = "<?php echo $row['name']; ?>"><?php echo $row['contact'];?></td>
<td data-name = "<?php echo $row['name']; ?>"><?php echo $row['department'];?></td>
<td data-name = "<?php echo $row['name']; ?>"><i class="fas fa-edit btnedit"></i></td>
</tr>
<?php
}
Your code works fine except one little thing: all your input selectors lack closing quote and bracket, e.g. this is wrong (jQuery 3.3.1 throws error):
let sname = $("input[name*='name_type");
But this is right:
let sname = $("input[name*='name_type']");
Otherwise, it works just fine (well, certain optimizations can be done, that's true, but still it works as is) -- if I have guessed your HTML structure correctly, see example below. (Disclaimer: this is by no means a good piece of code with best pracrices etc. This is just a reproduction of original task with minimal fix to make it work.)
$(document).ready(e => {
$(".btnedit").click(e => {
textvalues = displayData(e);
let sname = $("input[name*='name_type']");
let sage = $("input[name*='age_type']");
let sgender = $("input[name*='gender_type']");
sname.val(textvalues[0]);
sage.val(textvalues[1]);
sgender.val(textvalues[2]);
});
});
function displayData(e) {
let i = 0;
const td = $("#tbody tr td");
let textvalues = [];
for (const value of td) {
if (value.dataset.name == e.target.dataset.name) {
textvalues[i++] = value.textContent;
}
}
return textvalues;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tbody id="tbody">
<tr>
<td data-name="1">a1</td>
<td data-name="1">b1</td>
<td data-name="1">c1</td>
<td><button class="btnedit" data-name="1">edit</button></td>
</tr>
<tr>
<td data-name="2">a2</td>
<td data-name="2">b2</td>
<td data-name="2">c2</td>
<td><button class="btnedit" data-name="2">edit</button></td>
</tr>
</tbody>
</table>
Type: <input type="text" name="name_type" /><br />
Age: <input type="text" name="age_type" /><br />
Gender: <input type="text" name="gender_type" />
Possible reason of could be this: data-name is invalid everywhere in your table. If that's not the case, please share some more code. Minimal yet complete example would be great.
Update: in your example HTML I see no data-name attributes at all, and clickable element also does not have it. So, your selector $('#tbody th td') matches all TDs, and that's why you see whole table in output.
So, look at the example above and do the same with data-name: every <td> and the button on one row have the same value in that attribute.

calculation of two input field into third input field having multiple table rows in jquery

I am doing calculation in the third input field based on the value filled in the two input field. And here I have multiple row. Each row calculation should be done separately so i am using each function. But the calculation is not working.
I am new in Jquery so where code is getting wrong??
<table>
<tr>
<th><?= __('Quantity Offered')?></th>
<th><?= __('Offer Price')?></th>
<th><?= __('Total Offer Price')?></th>
</tr>
<tr class="productNRow">
<td><?php echo $this->Form->input("supplier_offer_products.0.qty_offered",['id'=>'qtyOffered']);?></td>
<td><?php echo $this->Form->input("supplier_offer_products.0.offer_price",['id'=>'priceOffered']);?></td>
</tr>
<tr class="productNRow">
<td><?php echo $this->Form->input("supplier_offer_products.1.qty_offered",['id'=>'qtyOffered']);?></td>
<td><?php echo $this->Form->input("supplier_offer_products.1.offer_price",['id'=>'priceOffered']);?></td>
</tr>
</table>
<script>
$(document).ready(function(){
$(".productNRow").each(function(){
var sentRec = $(this);
var total;
$(this).find("#qtyOffered").on('change', function () {
var qty = $(sentRec).find("#qtyOffered").val();
var offer = $(sentRec).find("#priceOffered").val();
var total = qty * offer;
$('#totalOrder').val(total);
});
});
});
You cannot have multiple IDs. Use classes and add the missing #totalOrder elements.
The jQuery and PHP than could look like this:
jQuery(function( $ ) {
$(".productNRow").each(function() {
var $row = $(this);
var $qty = $row.find(".qtyOffered"); // use classes! (see PHP too)
var $prc = $row.find(".priceOffered");
var $tot = $row.find(".totalOrder");
$qty.on('input', function() {
var qty = $(this).val();
var offer = $prc.val();
var total = qty * offer;
$tot.val(total);
});
});
});
<table>
<tr>
<th>Quantity Offered</th>
<th>Offer Price</th>
<th>Total Offer Price</th>
</tr>
<tr class="productNRow">
<td>
<?php echo $this->Form->input("supplier_offer_products.0.qty_offered",['class'=>'qtyOffered']);?>
</td>
<td>
<?php echo $this->Form->input("supplier_offer_products.0.offer_price",['class'=>'priceOffered']);?>
</td>
<td>
<input class="totalOrder">
</td>
</tr>
<tr class="productNRow">
<td>
<?php echo $this->Form->input("supplier_offer_products.1.qty_offered",['class'=>'qtyOffered']);?>
</td>
<td>
<?php echo $this->Form->input("supplier_offer_products.1.offer_price",['class'=>'priceOffered']);?>
</td>
<td>
<input class="totalOrder">
</td>
</tr>
</table>
or going the other way around (input→parent→inputs) without using the .each() method
jQuery(function( $ ) {
$(".qtyOffered").on('input', function() {
var $row = $(this).closest(".productNRow");
var $prc = $row.find(".priceOffered");
var $tot = $row.find(".totalOrder");
var qty = $(this).val();
var offer = $prc.val();
var total = qty * offer;
$tot.val(total);
});
});

JQuery tablesorting code not working (no plugin)

I'm displaying a table with AJAX in my website. I wrote a JQuery code for sorting my table when it's send via AJAX and a <th>-tag is clicked. (I don't want to use a plugin. No, really, I don't want to use a plugin!)
This is my code:
PHP (index.php):
<form action="query.php" method="get">
<input type="search" name="query" autofocus="true" autocomplete="off" list="products">
<datalist id="products">
<?php
$sql = "SELECT * FROM products;";
$result = mysqli_query($con, $sql);
while ($product = mysqli_fetch_array($result)) {
echo "<option value=\"" . $product["productname"] . "\">" . $product["price"] . " $</option>";
}
?>
</datalist>
<button type="submit">Search</button>
</form>
<div class="result" align="center"></div>
PHP (query.php):
<?php
include_once "connection.php";
$query = trim($_GET["query"]);
$query = mysqli_real_escape_string($con, $query);
$sql = "SELECT * FROM products WHERE productname LIKE '%$query%' ORDER BY productname;";
$result = mysqli_query($con, $sql);
$result_no = mysqli_num_rows($result);
if ($result_no > 0) {
echo "<table>";
echo "<thead>";
echo "<tr>";
echo "<th>Product</th>";
echo "<th>Price</th>";
echo "<th>Quantity</th>";
echo "</tr>";
echo "</thead>";
echo "<tbody>";
while ($product = mysqli_fetch_array($result)) {
echo "<tr class=\"table\"><td align=\"left\">" . $product["productname"] . "</td><td align=\"right\">" . $product["price"] . " $</td><td align=\"right\">" . $product["quantity"] . "</td></tr>";
}
echo "</tbody>";
echo "<tfoot>";
if ($result_no == 1) {
echo "<tr><td colspan=\"3\" align=\"center\">" . $result_no . " product found." . "</td></tr>";
} else {
echo "<tr><td colspan=\"3\" align=\"center\">" . $result_no . " product found." . "</td></tr>";
}
echo "</tfoot>";
echo "</table>";
} elseif ($result_no <= 0) {
echo "<p>No products found.</p>";
}
mysqli_close($con);
?>
JQuery:
$(document).ready(function() {
$("form").on("submit", function(event) {
event.preventDefault();
var form = $(this);
$.ajax({
type: this.method,
url: this.action,
data: form.serialize(),
cache: false,
success: function(data) {
$("div.result").html(data);
$("th").on("click", function() {
var column = $(this).index();
var tbody = $("tbody");
var rows = tbody.find("tr");
var dir = $(this).data("dir") || -1;
dir *= -1;
rows.sort(function(a, b) {
var aVal = $($(a).find("td")[column]).text().toLowerCase();
var bVal = $($(b).find("td")[column]).text().toLowerCase();
return aVal > bVal ? 1 * dir : aVal < bVal ? -1 * dir : 0;
});
$(this).data("dir", dir);
tbody.empty();
$(rows).appendTo(tbody);
});
}
});
});
});
The connection.php is for connecting to my database. I use MySQL and PHPMyAdmin. My tables are 'users' for login data and 'products' for the shop products.
My Problem: The first line of the table is alway sorted at the wrong place.
Use the built in javascript sort function.
I extracted the relevant sort code from your example
I grabbed a sample table from w3cschools
I modified the js to store the sorted direction in the header cell.
I implemented a compare function (see linked sort documentation).
I replaced the tbody when the sort was complete.
EDIT: changed out HTML, added functionality to function to enable numeric sorting and not just alphabetically. Note the number class and the new if in the sort function
$("th").on("click", function() {
var column = $(this).index();
var numeric = $(this).hasClass("number"); //this class has been sprinkled to identify numeric sort.
var bdy = $(this).closest("table").find("tbody");
var rows = bdy.find("tr");
var dir = $(this).data("dir") || -1; //default direction is desc
dir *= -1; //reverse the stored direction
rows.sort(function(a, b) {
var aVal = $($(a).find("td")[column]).text().toLowerCase(); //get the text from one row
var bVal = $($(b).find("td")[column]).text().toLowerCase(); //get the text from row 2
if (numeric) { //added to handle numeric columns
aVal = parseFloat(aVal);
bVal = parseFloat(bVal);
}
return aVal > bVal ? 1 * dir : aVal < bVal ? -1 * dir : 0; // note the dir value to change direction
}); //sort the rows by the column content
bdy.empty(); //empty the body
$(rows).appendTo(bdy); //put the rows back
$(this).data("dir", dir); //log the direction
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table">
<thead>
<tr class="table">
<th class="table">Product</th>
<th class="table number">Price</th>
<th class="table number">Quantity</th>
</tr>
</thead>
<tbody>
<tr class="table">
<td align="left" class="table">Chainsaw</td>
<td align="right" class="table">60.00 $</td>
<td align="right" class="table">1</td>
</tr>
<tr class="table">
<td align="left" class="table">Hammer</td>
<td align="right" class="table">24.99 $</td>
<td align="right" class="table">2</td>
</tr>
<tr class="table">
<td align="left" class="table">Nails (25 per Box)</td>
<td align="right" class="table">9.99 $</td>
<td align="right" class="table">21</td>
</tr>
<tr class="table">
<td align="left" class="table">Screwdriver</td>
<td align="right" class="table">29.99 $</td>
<td align="right" class="table">2</td>
</tr>
<tr class="table">
<td align="left" class="table">Screws (25 per Box)</td>
<td align="right" class="table">15.00 $</td>
<td align="right" class="table">26</td>
</tr>
</tbody>
<tfoot>
<tr class="table">
<td colspan="3" align="center" class="table">5 products found.</td>
</tr>
</tfoot>
</table>
#FelixRewer, please include a sample rendered table, your question was updated with your PHP. I believe that the PHP is not your problem but the HTML that comes out the other end.
Yes, maybe you're right. So here's a code snippet with the output of query.php and the JQuery tablesorter (I also added my styles, I don't think it's relevant, but if yes, here it is.):
$("th").on("click", function() {
var column = $(this).index();
var table = $("table");
var tbody = table.find("tbody");
var rows = tbody.find("tr");
var dir = $(this).data("dir") || -1;
dir *= -1;
rows.sort(function(a, b) {
var aVal = $($(a).find("td")[column]).text().toLowerCase().trim();
var bVal = $($(b).find("td")[column]).text().toLowerCase().trim();
return aVal > bVal ? 1 * dir : aVal < bVal ? -1 * dir : 0;
});
$(this).data("dir", dir);
tbody.empty();
$(rows).appendTo(table);
});
.table {
margin: 3vmax;
border: 1px solid #000000;
border-collapse: collapse;
color: #000000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table">
<thead>
<tr class="table">
<th class="table">Product</th>
<th class="table">Price</th>
<th class="table">Quantity</th>
</tr>
</thead>
<tbody>
<tr class="table">
<td align="left" class="table">Chainsaw</td>
<td align="right" class="table">60.00 $</td>
<td align="right" class="table">1</td>
</tr>
<tr class="table">
<td align="left" class="table">Hammer</td>
<td align="right" class="table">24.99 $</td>
<td align="right" class="table">2</td>
</tr>
<tr class="table">
<td align="left" class="table">Nails (25 per Box)</td>
<td align="right" class="table">9.99 $</td>
<td align="right" class="table">21</td>
</tr>
<tr class="table">
<td align="left" class="table">Screwdriver</td>
<td align="right" class="table">29.99 $</td>
<td align="right" class="table">2</td>
</tr>
<tr class="table">
<td align="left" class="table">Screws (25 per Box)</td>
<td align="right" class="table">15.00 $</td>
<td align="right" class="table">26</td>
</tr>
</tbody>
<tfoot>
<tr class="table">
<td colspan="3" align="center" class="table">5 products found.</td>
</tr>
</tfoot>
</table>
And yes I have the same problem here. I've tested a lot with my code and I think maybe the first line gets sorted at the wrong place, because of the <tfoot>, but that's just an assumption.
This topic is closed. Here's the code I was looking for:
JavaScript: https://jsfiddle.net/tf4e97w6/#&togetherjs=TGIj8qdzUO
jQuery: https://jsfiddle.net/15ke8Lqv/#&togetherjs=DACQV5mE9F
Code snippet:
$(document).ready(function() {
$("th").on("click", function() {
var column = $(this).index();
var table = $("table");
var tbody = table.find("tbody");
var rows = tbody.find("tr");
var dir = $(this).data("dir") || -1;
dir *= -1;
$(this).siblings().data("dir", -1);
rows.sort(function(a, b) {
var aVal = $($(a).find("td")[column]).html().toLowerCase().trim();
var bVal = $($(b).find("td")[column]).html().toLowerCase().trim();
if ($.isNumeric(aVal.charAt()) && $.isNumeric(bVal.charAt())) {
aVal = parseFloat(aVal);
bVal = parseFloat(bVal);
}
return aVal > bVal ? 1 * dir : aVal < bVal ? -1 * dir : 0;
});
$(this).data("dir", dir);
tbody.empty();
$(rows).appendTo(table);
});
});
h1 {
color: #cc1100;
}
table {
width: 100%;
}
table,
tr,
td {
border: 1px solid #000000;
border-collapse: collapse;
}
tfoot,
thead {
text-align: center;
background-color: #cccccc;
}
th:hover {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<caption>
<h1>Tablesorter</h1>
</caption>
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tbody>
<tr>
<td>January</td>
<td>$150</td>
</tr>
<tr>
<td>February</td>
<td>$160</td>
</tr>
<tr>
<td>March</td>
<td>$240</td>
</tr>
<tr>
<td>April</td>
<td>$160</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2">Sum: $710</td>
</tr>
</tfoot>
</table>
With kind regards,
Felix Rewer.

Parse (string)table with parent tr´s into array

I have a string with a table inside; my problem is to put the parent tr´s (according their childs) into array (for later using it is not important whether array is one- or multidimensional)
The table looks like this:
<tr><td class="boys" colspan="4"></td></tr>
<tr><td class="indoor" colspan="4"></td></tr>
<tr class="toy">
<td class="article">Ball</td>
<td class="color">Red</td>
<td class="size">big</td>
<td class="price">10</td>
</tr>
<tr class="toy">
<td class="article">Puzzle</td>
<td class="color">colored</td>
<td class="size">medium</td>
<td class="price">5</td>
</tr>
<tr><td class="outdoor" colspan="4"></td></tr>
<tr class="toy">
<td class="article">Inliner</td>
<td class="color">black</td>
<td class="size">5</td>
<td class="price">15</td>
</tr>
<tr class="toy">
<td class="article">Pool</td>
<td class="color">white/blue</td>
<td class="size">big</td>
<td class="price">25</td>
</tr>
<tr><td class="all" colspan="4"></td></tr>
<tr class="toy">
<td class="article">Book</td>
<td class="color">colored</td>
<td class="size">small</td>
<td class="price">2</td>
</tr>
and same tr/td construct for girls.
With
$html = str_get_html($e);
$toys= array();
foreach ( $html->find('tr[class=toy]') as $toy) {
$item['article'] = trim($toys->find('td', 0)->plaintext);
$item['color'] = trim($toys->find('td', 1)->plaintext);
$item['size'] = trim($toys->find('td', 2)->plaintext);
$item['price'] = trim($toys->find('td', 3)->plaintext);
$toys[] = $item;
}
How can i get both parents? So that array looks like
[0] => Array
(
[sex] => boys
[place] => indoor
[article] => Puzzle
[color] => colored
[size] => medium
[price] => 5
)
trying to get it with
$item['place'] = $toys->find('tr.toy', 0)->plaintext;
give wrong results...
You haven't posted the complete table structure (for girls as well), so I assume it looks like this:
<table id="products">
<tr><td class="boys" colspan="4"></td></tr>
<tr><td class="indoor" colspan="4"></td></tr>
<tr class="toy">...</tr>
<tr><td class="outdoor" colspan="4"></td></tr>
<tr class="toy">...</tr>
<tr><td class="girls" colspan="4"></td></tr>
<tr><td class="indoor" colspan="4"></td></tr>
<tr class="toy">...</tr>
<tr><td class="outdoor" colspan="4"></td></tr>
<tr class="toy">...</tr>
</table>
As I wanted to familiarize with the Simple DOM Parser Package, this was a welcome exercise for me. I leave the code as is. I hope it isn't against SO-Rules to omit explanations. So if an angry admin disagrees, or the OP wants some additional info, leave another answer here and I'll provide it in the future. Please regard the table-attribute id.
$ret = $html->find("table[id=products] tr");
$items = array();
$item = NULL;
foreach($ret as $r)
{
echo "got in the loop<br>";
$class = $r->getAttribute("class");
echo "class: $class<br>";
if (strlen(trim($class)) == 0)
{
echo "We have a <tr> without a class<br>";
$td = $r->firstChild();
$class = $td->getAttribute("class");
echo "The <td>-child should either have class boys,girls, indoor or outdoor<br>";
if (strcasecmp($class, "girls") == 0 ||
strcasecmp($class, "boys") == 0)
{
$sex = $class;
echo "It's a $sex<br>";
}
else
{
if (strcasecmp($class, "indoor") == 0 ||
strcasecmp($class, "outdoor") == 0)
{
$place = $class;
echo "Item is meant for $place-usage<br>";
}
}
}
else
{
$childs = $r->childNodes();
$item = array();
$item["place"] = $place;
$item["sex"] = $sex;
echo "Creating new item for $place-$sex<br>";
foreach($childs as $child)
{
$class = $child->getAttribute("class");
$item[$class] = $child->innertext;
echo "Item attribute $class with ".$child->innertext."<br>";
}
array_push($items, $item);
}
}
echo "<pre>";
print_r($items);
echo "</pre>";

Categories