How to create a searchbar with JavaScript - javascript

Hello Im trying to create a searchbar for my table with javascript and works but with some issues. The problem is when I try to search in two rows. For example if I only search in Name works! but if I search Name and Last Name doesn't work.
Here is my js function
var textbuscar = document.getElementById("buscar");
textbuscar.onkeyup = function() {
buscar(this);
}
function buscar(inputbuscar) {
var valorabuscar = (inputbuscar.value).toLowerCase().trim();
var tabla_tr = document.getElementById("tabla").getElementsByTagName("tbody")[0].rows;
for (var i = 0; i < tabla_tr.length; i++) {
var tr = tabla_tr[i];
var textotr = (tr.innerText).toLowerCase();
tr.className = (textotr.indexOf(valorabuscar) >= 0) ? "mostrar" : "ocultar";
}
}
Here is a runnable copy:
var textbuscar = document.getElementById("buscar");
textbuscar.onkeyup = function(){
buscar(this);
}
function buscar(inputbuscar){
var valorabuscar = (inputbuscar.value).toLowerCase().trim();
var tabla_tr = document.getElementById("tabla").getElementsByTagName("tbody")[0].rows;
for(var i=0; i<tabla_tr.length; i++){
var tr = tabla_tr[i];
var textotr = (tr.innerText).toLowerCase();
tr.className = (textotr.indexOf(valorabuscar)>=0)?"mostrar":"ocultar";
}
}
.mostar{display:block;}
.ocultar{display:none;}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<linl rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css">
<div class="container-fluid">
<div class="row">
<div class="col-xs-12">
<h1 class="page-header">
My Table
</h1>
<!-- TABLA INICIA -->
<table id="tabla" class="table table-striped">
<thead>
<tr>
<th style="width:160px">Nombre</th>
<th>Apellido</th>
<th style="width:220px">Profesion</th>
<th style="width:140px">Sueldo</th>
</tr>
<tr>
<td colspan="4">
<input id="buscar" type="text" class="form-control" placeholder="Escriba algo para filtrar" />
</td>
</tr>
</thead>
<tbody>
<tr>
<td>Juan</td>
<td>Perez Patiño</td>
<td>Marketing Empresarial</td>
<td class="text-right">S/. 9000.00</td>
</tr>
<tr>
<td>Alberto</td>
<td>Gonzales Flores</td>
<td>Derecho</td>
<td class="text-right">S/. 4000.00</td>
</tr>
<tr>
<td>Gustavo</td>
<td>Bueno Bravo</td>
<td>Derecho</td>
<td class="text-right">S/. 7000.00</td>
</tr>
<tr>
<td>Enrique</td>
<td>Pacheco Perez</td>
<td>Derecho</td>
<td class="text-right">S/. 12000.00</td>
</tr>
<tr>
<td>Jaime</td>
<td>Andrade Gonzales</td>
<td>Economia</td>
<td class="text-right">S/. 7500.00</td>
</tr>
<tr>
<td>Andrea</td>
<td>Loayza Perez</td>
<td>Medicina Humana</td>
<td class="text-right">S/. 7500.00</td>
</tr>
<tr>
<td>Elvira</td>
<td>Gonzales Perez</td>
<td>Ingeniería de Sistema</td>
<td class="text-right">S/. 7500.00</td>
</tr>
<tr>
<td>Joseph</td>
<td>Rodriguez Pacheco</td>
<td>Ingeniería de Software</td>
<td class="text-right">S/. 8200.00</td>
</tr>
<tr>
<td>Pedro</td>
<td>kuczynski</td>
<td>Economista</td>
<td class="text-right">S/. 250000.00</td>
</tr>
<tr>
<td>Alan</td>
<td>García Perez</td>
<td>Derecho</td>
<td class="text-right">S/. 120000.00</td>
</tr>
<tr>
<td>Jose</td>
<td>Villanueva Salvador</td>
<td>Medicina Humana</td>
<td class="text-right">S/. 2900.00</td>
</tr>
<tr>
<td>Alberto</td>
<td>Lozano García</td>
<td>Medicina Humana</td>
<td class="text-right">S/. 2900.00</td>
</tr>
</tbody>
</table>
<!-- TABLA FINALIZA -->
</div>
</div>
</div>
A demo at jsFiddle to play with.

To give you a headstart, I modified your function a little bit. This still doesn't work the way you want, but it should guide you with an idea:
function buscar(inputbuscar){
var valorabuscar = (inputbuscar.value).toLowerCase().trim();
var arraydevalores = valorabuscar.split(" ");
console.log(arraydevalores); //CHECK WHAT THIS LOGS
var tabla_tr = document.getElementById("tabla").getElementsByTagName("tbody")[0].rows;
console.log(findOne(arraydevalores, tabla_tr));
for(var i=0; i<tabla_tr.length; i++){
var tr = tabla_tr[i];
var textotr = (tr.innerText).toLowerCase();
tr.className = (textotr.indexOf(valorabuscar)>=0)?"mostrar":"ocultar";
}
}
I split your valorabuscar variable where any spaces are, so now you have an array of the terms that the user is searching for sepparately in an array that looks like this:
["juan", "pérez", "patiño"]
This array is easier to manipulate so as to compare it with your table and return whatever's more similar to it. Good luck!
PS: Here's an appropriate question to help you continue: Check if an array contains any element of another array in JavaScript

Related

Javascript Filtering by multiple columns

Borrowing code from the post below I am able to filter on 2 columns using the || (Or) operator.
However, I'd like to be able to filter using the && (And) operator.
I have been unsuccessful in my multiple attempts. I could use some help.
Filtering table multiple columns
function myFunction() {
var input0, input1, filter0, filter1, table, tr, td, cell, i, j;
document.getElementById("myInput0").value = 'Female';
document.getElementById("myInput1").value = 'Engineering';
input0 = document.getElementById("myInput0");
input1 = document.getElementById("myInput1");
filter0 = input0.value.toUpperCase();
filter1 = input1.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 1; i < tr.length; i++) {
// Hide the row initially.
tr[i].style.display = "none";
td = tr[i].getElementsByTagName("td");
for (var j = 0; j < td.length; j++) {
cell = tr[i].getElementsByTagName("td")[j];
if (cell) {
if (cell.textContent.toUpperCase().indexOf(filter0)>-1 ||
cell.textContent.toUpperCase().indexOf(filter1)>-1) {
tr[i].style.display = "";
break;
}
}
}
}
}
<body>
<input type="text" id="myInput0">
<input type="text" id="myInput1">
<input type='button' onclick='myFunction()' value='click me' />
<table id="myTable">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Gender</th>
<th>Department</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Doe</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Mary</td>
<td>Moe</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>July</td>
<td>Dooley</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>Anja</td>
<td>Ravendale</td>
<td>Female</td>
<td>Engineering</td>
</tr>
<tr>
<td>Thomas</td>
<td>Dubois</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Deidre</td>
<td>Masters</td>
<td>Female</td>
<td>Sales</td>
</tr>
<tr>
<td>Sean</td>
<td>Franken</td>
<td>Male</td>
<td>Engineering</td>
</tr>
</tbody>
</table>
</body>
For each cell, you can check each filter separately, then only change the DOM for rows where all filter conditions are met.
(This example uses a restructured version of your code.)
document.getElementById("myInput0").value = 'Female';
document.getElementById("myInput1").value = 'Engineering';
const
input0 = document.getElementById("myInput0"),
input1 = document.getElementById("myInput1"),
table = document.getElementById("myTable"),
rows = table.getElementsByTagName("tr");
function myFunction() {
filter0 = input0.value.toUpperCase(),
filter1 = input1.value.toUpperCase();
for (let row of rows) {
row.classList.add("hidden");
const cells = row.getElementsByTagName("td");
let
filter0met = false,
filter1met = false;
for (let cell of cells) {
if (cell.textContent.toUpperCase().includes(filter0)) {
filter0met = true;
}
if (cell.textContent.toUpperCase().includes(filter1)) {
filter1met = true;
}
}
if (filter0met && filter1met) {
row.classList.remove("hidden");
}
}
}
.hidden {
display: none;
}
<body>
<input type="text" id="myInput0"><input type="text" id="myInput1"><input type='button' onclick='myFunction()' value='click me' />
<table id="myTable">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Gender</th>
<th>Department</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Doe</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Mary</td>
<td>Moe</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>July</td>
<td>Dooley</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>Anja</td>
<td>Ravendale</td>
<td>Female</td>
<td>Engineering</td>
</tr>
<tr>
<td>Thomas</td>
<td>Dubois</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Deidre</td>
<td>Masters</td>
<td>Female</td>
<td>Sales</td>
</tr>
<tr>
<td>Sean</td>
<td>Franken</td>
<td>Male</td>
<td>Engineering</td>
</tr>
</tbody>
</table>
</body>
After much trial and error for I was able to put together some JQuery that will dynamically search the first input, and then search those results for the second input. Note, I am using SP2016. While I've included it here in my post, I could not get the call to "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" to work. I found downloading and storing the file on my SharePoint site worked. For my requirement I wanted to display my list with grouped rows so I'm using a function to collapse the groups on load. The caveat is the groups in listview have to be configured as expanded.
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript"src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></SCRIPT>
<script>
//If rows are not grouped, remove this function
$(window).load(function () {
$(".ms-commentcollapse-icon").click();
});
$(document).ready(function() {
$("#myInput").on("keyup", function() {
var value = this.value.toLowerCase();
//If rows are not grouped, remove this line
$(".ms-commentexpand-icon").click();
$('.ms-listviewtable > tbody > tr').addClass('myInputMismatch').filter(function() {
return this.innerHTML.toLowerCase().indexOf(value) > -1;
}).removeClass('myInputMismatch');
});
$("#myInput1").on("keyup", function() {
var value = this.value.toLowerCase();
$('.ms-listviewtable > tbody > tr').addClass('myInput1Mismatch').filter(function() {
return this.innerHTML.toLowerCase().indexOf(value) > -1;
}).removeClass('myInput1Mismatch');
});
});
</script>
<style>
.myInputMismatch, .myInput1Mismatch { display: none; }
</style></head>
<input id="myInput" type="text" Placeholder="Search here 1st..."><input id="myInput1" type="text" Placeholder="Search here 2nd...">

Get value of only that style attribute who have font family

Html Code:
<table style="width:100%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px;">Jill</td>
<td>Smith</td>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px;">50</td>
</tr>
<tr>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px;">Eve</td>
<td>Jackson</td>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px; color:#666; font-weight:bold;
text-decoration:none;margin:0;padding:0;text-align:left;white-space:nowrap;">94</td>
</tr>
</table>
Javascript Code:
<script>
var tg_name = document.getElementsByTagName("td");
var l_tgname = tg_name.length;
array_get = [];
for(h=0;h<=l_tgname;h++){
var val_gt_chck = document.getElementsByTagName("td")[h].hasAttribute("style");
if(val_gt_chck){
var val_gt = document.getElementsByTagName("td")[h].getAttribute("style");
if(val_gt!==null && val_gt !== ''){
check_words = val_gt.includes('font-family');
if(check_words){
alert(val_gt);
array_get.push(val_gt);
}
}
}
}
alert(array_get);
</script>
I wanted to combine all the data in one variable and access that variable outside the loop.It give the error that "Cannot read property 'has Attribute' of undefined"
There was wrong for condition and includes replaced by indexOf for better compatibility:
var tg_name = document.getElementsByTagName("td");
var l_tgname = tg_name.length;
array_get = [];
for(h=0;h<l_tgname;h++){
var val_gt_chck = document.getElementsByTagName("td")[h].hasAttribute("style");
if(val_gt_chck){
var val_gt = document.getElementsByTagName("td")[h].getAttribute("style");
if(val_gt!==null && val_gt !== ''){
check_words = val_gt.indexOf('font-family:') > -1;
if(check_words){
console.log(val_gt);
array_get.push(val_gt);
}
}
}
}
console.log(array_get);
<table style="width:100%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px;">Jill</td>
<td>Smith</td>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px;">50</td>
</tr>
<tr>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px;">Eve</td>
<td>Jackson</td>
<td style="font-family:Helvetica,Arial,sans-serif;font-size:13px; color:#666; font-weight:bold;
text-decoration:none;margin:0;padding:0;text-align:left;white-space:nowrap;">94</td>
</tr>
</table>

td element not parsed to int

I have a table with id #tab1.
For each row, I want to calculate the value of column Points / Matches and to put it in the column Coeficiency, but my code doesn't work.
The numbers aren't parsed to int. I would always like to know if
elem[4].innerHTML(z); is ok to set coeficiency.
Average();
function Average() {
var table = document.getElementById('tab1'),
rows = table.getElementsByTagName('tbody')[1].getElementsByTagName('tr');
//console.log(rows.length);
for (var i = 0; i < rows.length; i++) {
elem = rows[i].getElementsByClassName("columns");
var x = parseInt(elem[2]);
var y = parseInt(elem[3]);
// console.log(x+y," ");
console.log(x, " ", y);
var z = y / x;
elem[4].innerHTML(z);
}
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</th>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
</tr>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>
Okay, so a few pointers having looked over your code, first of all innerHTML is not a function, it's a simple property, you can just reassign it, however, I suggest using textContent due to the fact that using innerHTML, you can allow for XSS to occur.
I mean I know XSS probably isn't an issue in this specific scenario, however I thought it my be of value mentioning that.
Also, as I mentioned in the comments above, using parseInt, you need to pass it a string rather than an object which is what you were originally doing. Using functions such as getElementsByClassName or querySelectorAll, you'll have an array-like object, such as a HTMLCollection which contains a number of objects, usually Elements or Nodes.
Average();
function Average() {
var table = document.getElementById('tab1'),
rows = table.getElementsByTagName('tbody')[1].getElementsByTagName('tr');
//console.log(rows.length);
for (var i = 0; i < rows.length; i++) {
elem = rows[i].getElementsByClassName("columns");
var x = parseInt(elem[2].textContent);
var y = parseInt(elem[3].textContent);
// console.log(x+y," ");
console.log(x, " ", y);
var z = y / x;
elem[4].textContent = z;
}
}
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</th>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
</tr>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>
Edit
I thought I'd also include a neater version, it does near enough the same logic stuff, it's more or less just more modern JavaScript syntax, using a more 'functional-style'. Originally I basically copied the exact same style that you provided for the sake of simplicity, but I thought that there's a few issues with that. An example being how you've used a capital letter for the Average, personally I only use a capital letter at the start of a name if it's a class, this is a personal choice however, feel free to disagree or stick to what you know!
I personally prefer using more modern syntax as personally I think is easier to read, it's more clear and concise, generally it looks like less code to read through.
// States if an array like object is empty or not.
const isEmpty = a => a.length > 0;
// Returns the text content of a html object.
const txt = td => td == null ? null : td.textContent;
// Simply updates the UI.
const render = tds => v => tds[4].textContent = parseFloat(v).toFixed(2);
// Works out whether or not to fire update or do nothing.
const compute = tds => isEmpty(tds) ? render(tds)(txt(tds[3]) / txt(tds[2])) : null;
// Gets the average for each tr.
const avg = trs => trs.forEach(tr => compute(tr.querySelectorAll("td")));
// Fire the avg function.
const update = () => avg(document.querySelectorAll("#tab1 tbody tr"));
// Render tr tag.
const renderTr = i => n => m => p => `<tr>
<td>${i}</td><td>${n}</td><td>${m}</td><td>${p}</td><td></td>
</tr>`;
// Add a table row.
const append = () => {
const tbl = document.getElementById("tab1");
const i = document.querySelectorAll("#tab1 tbody tr").length,
n = '_____',
m = Math.floor(Math.random() * 10) + 1,
p = Math.floor(Math.random() * 10) + 1;
// Safe-ish because what's being entered is controlled 100%.
// But generally try not to use innerHTML.
tbl.innerHTML += renderTr(i)(n)(m)(p);
update();
};
// Allow for auto add.
document.getElementById("add").onclick = append;
update(); // Initial run.
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</th>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
</tr>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>
<button id="add">Add Row</button>
Using Object#values Array#forEach #getElementsByTagName
The main issue is that you needed to retrieve the text value with innerText.
You also don't need the redundant class names.
const table = document.getElementById("table");
const rows = table.querySelectorAll("tbody > tr");
Object.values(rows).forEach(row => {
const tds = row.getElementsByTagName('td');
if (tds.length === 5) {
const x = parseInt(tds[2].innerText),
y = parseInt(tds[3].innerText);
const z = y / x;
tds[4].innerText = `${z}`;
}
});
<table id="table">
<tr>
<th>#</th>
<th>Team</th>
<th>Matches</th>
<th>Points</th>
<th>Coeficiency</th>
</tr>
<tbody>
<tr>
<td>1</td>
<td>Baetasii</td>
<td>3</td>
<td>9</td>
<td>100%</td>
</tr>
<tr>
<td>2</td>
<td>Carcotasii</td>
<td>2</td>
<td>5</td>
<td>100%</td>
</tr>
</tbody>
</table>
getElementsByClassName returns an array-like object of all child elements which have all of the given class names.
Since we have a collection of DOM elements, elem[2] it's a DOM element and you should access its textContent property.
Also, you're using innerHTML property in a wrong way. Just replace
elem[4].innerHTML(z);
to
elem[4].innerHTML = z;
Average();
function Average() {
var table = document.getElementById('tab1'),
rows = table.getElementsByTagName('tbody')[1].getElementsByTagName('tr');
for (var i = 0; i < rows.length; i++) {
elem = rows[i].getElementsByClassName("columns");
var x = parseInt(elem[2].textContent);
var y = parseInt(elem[3].textContent);
console.log(x, " ", y);
var z = y / x;
elem[4].innerHTML = z;
}
}
<div id="mytable">
<table id="tab1">
<tr class="rows">
<th class="columns">#</th>
<th class="columns">Team</th>
<th class="columns">Matches</ht>
<th class="columns">Points</th>
<th class="columns">Coeficiency</th>
<tbody>
<tr class="rows">
<td class="columns">1</td>
<td class="columns">Baetasii</td>
<td class="columns">3</td>
<td class="columns">9</td>
<td class="columns">100%</td>
</tr>
<tr class="rows">
<td class="columns">2</td>
<td class="columns">Carcotasii</td>
<td class="columns">2</td>
<td class="columns">5</td>
<td class="columns">100%</td>
</tr>
</tbody>
</table>
</div>

How to copy the contents of one row in a table to another table and add the identical ones

var Sell_Button = document.getElementById('sellbtn'),
secondTable = document.getElementById("secondTableBody");
Sell_Button.addEventListener('click', function() {
var Row = secondTable.insertRow();
for (var c = 0; c < 2; c += 1) {
Row.insertCell(c);
}
Row.cells[0].innerHTML = this.parentNode.parentNode.cells[0].innerHTML;
Row.cells[2].innerHTML = this.parentNode.parentNode.cells[1].innerHTML;
//checks to see if the secondTable has a row containing the same name
for (var f = 0; f < secondTable.rows.length; f += 1) {
//adds only the sold amount if the second table has a row with the same name
//error
if (secondTable.rows[f].cells[0].innerText === this.parentNode.parentNode.cells[0].innerText) {
secondTable.rows[f].cells[1].innerHTML = +this.parentNode.parentNode.cells[2].innerHTML;
//deletes an extra row that is added at the bottom
if (secondTable.rows.length > 1) {
secondTable.deleteRow(secondTable.rows.length - 1);
}
//if nothing matched then a new row is added
} else {
secondTable.insertRow();
Row.cells[0].innerHTML = this.parentNode.parentNode.cells[0].innerHTML;
Row.cells[1].innerHTML = this.parentNode.parentNode.cells[2].innerHTML;
}
}
}
}
<html>
<body>
<div id="firstTableDiv">
<table border="1" id="firstTable">
<thead>
<th>Item</th>
<th>Stock</th>
<th colspan="1">Sold</th>
</thead>
<tbody id="firstTableBody">
<tr>
<td>Apples</td>
<td>300</td>
<td>200</td>
<td>
<button id="sellbtn">Sell</button>
</td>
</tr>
<tr>
<td>Apples</td>
<td>300</td>
<td>100</td>
<td>
<button id="sellbtn">Sell</button>
</td>
</tr>
<tr>
<td>Oranges</td>
<td>400</td>
<td>300</td>
<td>
<button id="sellbtn">Sell</button>
</td>
</tr>
</tbody>
</table>
</div>
</br>
<div id="secondTableDiv">
Sold
<table border="1" id="secondTable">
<thead>
<th>Item</th>
<th>Sold</th>
</thead>
<tbody id="secondTableBody">
</tbody>
</table>
</div>
</body>
</html>
Ok, this example isn't exactly what i'm working on but it's very similar. The only difference is that in mine the rows and buttons are dynamically added by the user and he inserts the details. What I want is that when i press on the button of each row (sell) the details (Item and Sold only) are copied into a row in the second table and checks if the same item exists in this second table if so then it adds the amount of sold of both items in one row. For instance I press on the first row button the Apples it copies the listed above details to the second table in a row and then when i click on the button of the second row (Apples also) it only adds the sold amount up and doesn't add a second apples row because an apples row already exists in the second table but when i click on the oranges button it makes a new row because the oranges row doesn't exist. So how do I do this in JavaScript? i hope i was thorough and made any sense. I have no idea why the code isn't working here but i hope you get the point. This code works perfectly just as i want it to until for some reason i get this error: Cannot read property 'innerText' of undefined when i press the buttons approx. 6-7 times targeting the if statement where i commented error.
This sets a click handler to all buttons. If the row doesn't exist in the second table it's created. It sets a data-type referring to the item. When somebody clicks the sell button again and there is a row containing the data-type the row is updated instead of created. All in plain JavaScript.
var Sell_Button = document.querySelectorAll('.sellbtn'),
secondTable = document.getElementById("secondTableBody");
Array.prototype.slice.call(Sell_Button).forEach(function(element){
element.addEventListener('click', function(e) {
//since the button is an element without children use e.
var clickedElement = e.target;
var parentRow = clickedElement.parentNode.parentNode;
//check if second table has a row with data-type
var rowWithData = secondTable.querySelector("[data-type='"+parentRow.cells[0].childNodes[0].nodeValue+"']");
if (rowWithData)
{
rowWithData.cells[1].innerHTML = parseInt(rowWithData.cells[1].childNodes[0].nodeValue) + parseInt(parentRow.cells[2].childNodes[0].nodeValue);
}
else
{
var Row = secondTable.insertRow();
Row.setAttribute("data-type", parentRow.cells[0].childNodes[0].nodeValue);
for (var c = 0; c < 2; c += 1) {
Row.insertCell(c);
}
Row.cells[0].innerHTML = parentRow.cells[0].childNodes[0].nodeValue;
Row.cells[1].innerHTML = parentRow.cells[2].childNodes[0].nodeValue;
}
});
});
<html>
<body>
<div id="firstTableDiv">
<table border="1" id="firstTable">
<thead>
<th>Item</th>
<th>Stock</th>
<th colspan="1">Sold</th>
</thead>
<tbody id="firstTableBody">
<tr>
<td>Apples</td>
<td>300</td>
<td>200</td>
<td>
<button class="sellbtn">Sell</button>
</td>
</tr>
<tr>
<td>Apples</td>
<td>300</td>
<td>100</td>
<td>
<button class="sellbtn">Sell</button>
</td>
</tr>
<tr>
<td>Oranges</td>
<td>400</td>
<td>300</td>
<td>
<button class="sellbtn">Sell</button>
</td>
</tr>
</tbody>
</table>
</div>
</br>
<div id="secondTableDiv">
Sold
<table border="1" id="secondTable">
<thead>
<th>Item</th>
<th>Sold</th>
</thead>
<tbody id="secondTableBody">
</tbody>
</table>
</div>
</body>
</html>
Do you mean something like:
$(document).on("click", "#firstTable tr button", function(b) {
b = $(this).closest("tr");
var d = $.trim(b.find("td:first").text());
b = parseFloat($.trim(b.find("td:nth-child(3)").text()));
var a = $("#secondTable"),
c = a.find("tr").filter(function(a) {
return $.trim($(this).find("td:first").text()) == d
});
c.length ? (a = c.find("td:nth-child(2)"), c = parseFloat($.trim(a.text())), a.text(b + c)) : (a = $("<tr />").appendTo(a), $("<td />", {
text: d
}).appendTo(a), $("<td />", {
text: b
}).appendTo(a))
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="firstTableDiv">
<table border="1" id="firstTable">
<thead>
<tr>
<th>Item</th>
<th>Stock</th>
<th colspan="1">Sold</th>
</tr>
</thead>
<tbody id="firstTableBody">
<tr>
<td>Apples</td>
<td>300</td>
<td>200</td>
<td><button>Sell</button></td>
</tr>
<tr>
<td>Apples</td>
<td>300</td>
<td>100</td>
<td><button>Sell</button></td>
</tr>
<tr>
<td>Oranges</td>
<td>400</td>
<td>300</td>
<td><button>Sell</button></td>
</tr>
</tbody>
</table>
</div>
<br />
<div id="secondTableDiv">
Sold
<table border="1" id="secondTable">
<thead>
<tr>
<th>Item</th>
<th>Sold</th>
</tr>
</thead>
<tbody id="secondTableBody"></tbody>
</table>
</div>

merging <td> rows in one column of html table

I have a requirement, if i have same data in column1 of 's with same id then i need to merge those cells and show their respective values in column2.
i.e., in fiddle http://jsfiddle.net/7t9qkLc0/12/ the key column have 3rows with data 1 as row value with same id and has corresponding different values in Value column i.e., AA,BB,CC. I want to merge the 3 rows in key Column and display data 1 only once and show their corresponding values in separate rows in value column.
Similarly for data4 and data5 the values are same i.e.,FF and keys are different, i want to merge last 2 rows in Value column and dispaly FF only one time and show corresponding keys in key column. All data i'm getting would be the dynamic data. Please suggest.
Please find the fiddle http://jsfiddle.net/7t9qkLc0/12/
Sample html code:
<table width="300px" height="150px" border="1">
<tr><th>Key</th><th>Value</th></tr>
<tr>
<td id="1">data 1</td>
<td id="aa">AA</td>
</tr>
<tr>
<td id="1">data 1</td>
<td id="bb">BB</td>
</tr>
<tr>
<td id="1">data 1</td>
<td id="cc">CC</td>
</tr>
<tr>
<td id="2">data 2</td>
<td id="dd">DD</td>
</tr>
<tr>
<td id="2">data 2</td>
<td id="ee">EE</td>
</tr>
<tr>
<td id="3">data 3</td>
<td id="ff">FF</td>
</tr>
<tr>
<td id="4">data 4</td>
<td id="ff">FF</td>
</tr>
<tr>
<td id="5">data 5</td>
<td id="ff">FF</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="3" style="padding-left: 0px; padding-right: 0px; padding-bottom: 0px">
</td>
</tr>
</table>
Building on tkounenis' answer using Rowspan:
One option to implement what you need would be to read all the values in your table after being populated, then use a JS object literal as a data structure to figure out what rows/columns are unique.
A JS object literal requires a unique key which you can map values to. After figuring out what rows/columns should be grouped, you can either edit the original table, or hide the original table and create a new table (I'm creating new tables in this example).
I've created an example for you to create a new table either grouped by key or grouped by value. Try to edit the examples provided to introduce both requirements.
Let me know if you need more help. Best of luck.
JSFiddle: http://jsfiddle.net/biz79/x417905v/
JS (uses jQuery):
sortByCol(0);
sortByCol(1);
function sortByCol(keyCol) {
// keyCol = 0 for first col, 1 for 2nd col
var valCol = (keyCol === 0) ? 1 : 0;
var $rows = $('#presort tr');
var dict = {};
var col1name = $('th').eq(keyCol).html();
var col2name = $('th').eq(valCol).html();
for (var i = 0; i < $rows.length; i++) {
if ($rows.eq(i).children('td').length > 0) {
var key = $rows.eq(i).children('td').eq(keyCol).html();
var val = $rows.eq(i).children('td').eq(valCol).html();
if (key in dict) {
dict[key].push(val);
} else {
dict[key] = [val];
}
}
}
redrawTable(dict,col1name,col2name);
}
function redrawTable(dict,col1name,col2name) {
var $table = $('<table>').attr("border",1);
$table.css( {"width":"300px" } );
$table.append($('<tr><th>' +col1name+ '</th><th>' +col2name+ '</th>'));
for (var prop in dict) {
for (var i = 0, len = dict[prop].length; i< len; i++) {
var $row = $('<tr>');
if ( i == 0) {
$row.append( $("<td>").attr('rowspan',len).html( prop ) );
$row.append( $("<td>").html( dict[prop][i] ) );
}
else {
$row.append( $("<td>").html( dict[prop][i] ) );
}
$table.append($row);
}
}
$('div').after($table);
}
Use the rowspan attribute like so:
<table width="300px" height="150px" border="1">
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr>
<td id="1" rowspan="3">data 1</td>
<td id="aa">AA</td>
</tr>
<tr>
<td id="bb">BB</td>
</tr>
<tr>
<td id="cc">CC</td>
</tr>
<tr>
<td id="2" rowspan="2">data 2</td>
<td id="dd">DD</td>
</tr>
<tr>
<td id="ee">EE</td>
</tr>
<tr>
<td id="3">data 3</td>
<td id="ff">FF</td>
</tr>
<tr>
<td id="4">data 4</td>
<td id="ff">FF</td>
</tr>
<tr>
<td id="5">data 5</td>
<td id="ff">FF</td>
</tr>
</table>
http://jsfiddle.net/37b793pz/4/
Can not be used more than once the same id. For that use data-id attribute
HTML:
<table width="300px" height="150px" border="1">
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr>
<td data-id="key1">data 1</td>
<td data-id="valaa">AA</td>
</tr>
<tr>
<td data-id="key1">data 1</td>
<td data-id="valbb">BB</td>
</tr>
<tr>
<td data-id="key1">data 1</td>
<td data-id="valcc">CC</td>
</tr>
<tr>
<td data-id="key2">data 2</td>
<td data-id="valdd">DD</td>
</tr>
<tr>
<td data-id="key2">data 2</td>
<td data-id="valee">EE</td>
</tr>
<tr>
<td data-id="key3">data 3</td>
<td data-id="valff">FF</td>
</tr>
<tr>
<td data-id="key4">data 4</td>
<td data-id="valff">FF</td>
</tr>
<tr>
<td data-id="key5">data 5</td>
<td data-id="valff">FF</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="3" style="padding-left: 0px; padding-right: 0px; padding-bottom: 0px"></td>
</tr>
</table>
JQ:
//merge cells in key column
function mergerKey() {
// prevents the same attribute is used more than once Ip
var idA = [];
// finds all cells id column Key
$('td[data-id^="key"]').each(function () {
var id = $(this).attr('data-id');
// prevents the same attribute is used more than once IIp
if ($.inArray(id, idA) == -1) {
idA.push(id);
// finds all cells that have the same data-id attribute
var $td = $('td[data-id="' + id + '"]');
//counts the number of cells with the same data-id
var count = $td.size();
if (count > 1) {
//If there is more than one
//then merging
$td.not(":eq(0)").remove();
$td.attr('rowspan', count);
}
}
})
}
//similar logic as for mergerKey()
function mergerVal() {
var idA = [];
$('td[data-id^="val"]').each(function () {
var id = $(this).attr('data-id');
if ($.inArray(id, idA) == -1) {
idA.push(id);
var $td = $('td[data-id="' + id + '"]');
var count = $td.size();
if (count > 1) {
$td.not(":eq(0)").remove();
$td.attr('rowspan', count);
}
}
})
}
mergerKey();
mergerVal();
Use below snippet of javascript. It should work fine for what you are looking.
<script type="text/javascript">
function mergeCommonCells(table, columnIndexToMerge){
previous = null;
cellToExtend = null;
table.find("td:nth-child("+columnIndexToMerge+")").each(function(){
jthis = $(this);
content = jthis.text();
if(previous == content){
jthis.remove();
if(cellToExtend.attr("rowspan") == undefined){
cellToExtend.attr("rowspan", 2);
}
else{
currentrowspan = parseInt(cellToExtend.attr("rowspan"));
cellToExtend.attr("rowspan", currentrowspan+1);
}
}
else{
previous = content;
cellToExtend = jthis;
}
});
};
mergeCommonCells($("#tableId"), 1);
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>

Categories

Resources