I have a data table that I render in ASP.NET MVC using C# in a razor view.
To make a really short example of what I'm trying to achieve let's use this table as an example.
function setValueAttr(el) {
el.setAttribute('value', el.value)
}
function aplicar() {
var myTab = document.querySelectorAll('#tableID tbody tr .txtID:not([value=""])');
var tableData = [];
Array.from(myTab).forEach(input => {
var tds = input.closest('tr').children;
var obj = {};
obj.A = tds[0].textContent;
obj.B = tds[1].textContent;
obj.C = tds[2].textContent;
obj.D = tds[3].textContent;
obj.E = input.value;
tableData.push(obj);
});
console.log(tableData);
}
<table class="table table-bordered" width="100%" cellspacing="0" id="tableID">
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">val1</td>
<td align="center">val2</td>
<td align="center">val3</td>
<td align="center">1500</td>
<td align="center" class="myID"><input type="number" name="txtID" class="txtID" oninput="setValueAttr(this)" value="" min="0" max="1000"></td>
</tr>
<tr>
<td align="center">val1</td>
<td align="center">val2</td>
<td align="center">val3</td>
<td align="center">1500</td>
<td align="center" class="myID"><input type="number" name="txtID" class="txtID" oninput="setValueAttr(this)" value="" min="0" max="1000"></td>
</tr>
<tr>
<td align="center">val1</td>
<td align="center">val2</td>
<td align="center">val3</td>
<td align="center">1500</td>
<td align="center" class="myID"><input type="number" name="txtID" class="txtID" oninput="setValueAttr(this)" value="" min="0" max="1000"></td>
</tr>
</tbody>
</table>
<form>
<button type="button" onclick="aplicar()">Aplicar</button>
</form>
What this does is that it will pull data out of the rows that do have data inside the last input in the column E into an array
However I can input any amount of data even if I setup the attribute max="1000" on all of my inputs, how I can solve this?
In the MVC view instead of the static max value I have on this example I have a foreach for a data table that I get from a dataset, declaring it inside as #my_value will output different values inside the max="" attribute however this won't stop me from writing any value just like in this example
You can add a simple addition to your script function to check for max. I think unless you use observers you will have to check in your javasctipt
function aplicar() {
var myTab = document.querySelectorAll('#tableID tbody tr .txtID:not([value=""])');
var tableData = [];
Array.from(myTab).forEach(input => {
var tds = input.closest('tr').children;
var obj = {};
obj.A = tds[0].textContent;
obj.B = tds[1].textContent;
obj.C = tds[2].textContent;
obj.D = tds[3].textContent;
if(input.value > MAX)
{
input.value = MAX;
}
obj.E = input.value;
tableData.push(obj);
});
console.log(tableData);
}
Setting the attribute value with javascript is most likely circumventing the validation mechanism of the input element. Why do you set the value element using javascript? The value attribute is filled by typing a value into the input element by itself.
Added this attribute
var myTab = document.querySelectorAll('#tableID tbody tr .txtID:not([value=""]):valid');
And it fixed it, thanks a lot everyone, specially #HereticMonkey who solved the issue
Related
Sign up and first question. I keep looking to solve my problem but haven't found an answer yet. The question is, like the title, I want to load an excel file into an html table and give each td a different ID.
Currently, I have succeeded in assigning an id, but I know that the id value must not be the same. So I want to solve this problem with vanilla JavaScript. Below are the scripts I've completed so far and the results shown in the Chrome Developer Tools.
SCRIPT:
document.getElementById("ex_file").onchange = (evt) => {
var reader = new FileReader();
reader.addEventListener("loadend", (evt) => {
var table = document.getElementById("importexcel");
table.innerHTML = "";
var workbook = XLSX.read(evt.target.result, {type: "binary"}),
worksheet = workbook.Sheets[workbook.SheetNames[0]],
range = XLSX.utils.decode_range(worksheet["!ref"]);
for (let row=range.s.r; row<=range.e.r; row++) {
let r = table.insertRow();
for (let col=range.s.c; col<=range.e.c; col++) {
let c = r.insertCell(),
xcell = worksheet[XLSX.utils.encode_cell({r:row, c:col})];
c.innerHTML = xcell.v;
c.setAttribute('id', 'excel' + numbering)
var numbering = 0;
numbering++;
}
}
});
reader.readAsArrayBuffer(evt.target.files[0]);
};
Chrome Developer Tools:
<table id="importexcel" class="table">
<tbody>
<tr>
<td id="excelundefined">STYLE</td>
<td id="excel1">XS 90</td>
<td id="excel1">X 95</td>
<td id="excel1">M 100</td>
<td id="excel1">L 105</td>
<td id="excel1">XL 110</td>
<td id="excel1">XXL 115</td>
<td id="excel1">TOTAL</td>
</tr>
<tr>
<td id="excel1">hgfhgfhgf</td>
<td id="excel1">3</td>
<td id="excel1">4</td>
<td id="excel1">0</td>
<td id="excel1">4</td>
<td id="excel1">0</td>
<td id="excel1">4</td>
<td id="excel1">15</td>
</tr>
</tbody>
</table>
Below is the result I want:
<table id="importexcel" class="table">
<tbody>
<tr>
<td id="excelundefined">STYLE</td>
<td id="excel1">XS 90</td>
<td id="excel2">X 95</td>
<td id="excel3">M 100</td>
<td id="excel4">L 105</td>
<td id="excel5">XL 110</td>
<td id="excel6">XXL 115</td>
<td id="excel7">TOTAL</td>
</tr>
<tr>
<td id="excel8">hgfhgfhgf</td>
<td id="excel9">3</td>
<td id="excel10">4</td>
<td id="excel11">0</td>
<td id="excel12">4</td>
<td id="excel13">0</td>
<td id="excel14">4</td>
<td id="excel15">15</td>
</tr>
</tbody>
</table>
The script used another developer's script. If there is a problem, I would like to get help. Please feel free to comment if you need a little more information for an accurate answer!
I want to make X and O game , So the first function i did it has loop and condition that when i click on any cell(td) in the table and if all cells in the table are empty wrote X in the cell which I clicked it , but I have here 2 problem ,
First one The console wrote (Sample1.html:53 Uncaught SyntaxError: Unexpected token '<') it refers to for loop, so I don't know what is the problem there.
the second problem console wrote also that my function name is not define , although the function name is correct so can anyone help me.
the JS codes is
<script >
/*var lastGame;*/
var TR=0;
var table = document.getElementById('tb');
function CheckAllEmpty(idClicked){
for(var x=0, x < table.rows.length; x++){
if(!table.rows[x])
{
TR++;
}
else{}
}
if(TR==9)
{
document.getElementById(idClicked).innerHTML="X";
}
else {}
}
</script>
And the HTML :
<table id="tb">
<tr>
<td id="td1" onclick="CheckAllEmpty(this.id);"></td>
<td id="td2"></td>
<td id="td3"></td>
</tr>
<tr>
<td id="td4"></td>
<td id="td5"></td>
<td id="td6"></td>
</tr>
<tr>
<td id="td7"></td>
<td id="td8"></td>
<td id="td9"></td>
</tr>
</table>
There seems to be other problems with your code, but your two specific problems should be fixed. Also I don't see why you need to check if every cell is empty, but then again I can't see the rest of your code. Feel free to ask any questions in the comments.
var TR = 0;
var table = document.getElementById('tb');
function CheckAllEmpty(idClicked) {
for (var x = 0; x < table.rows.length; x++) {
if (!(table.rows[x].value == "")) {
TR++;
console.log(TR);
}
}
if (TR == 3) {
document.getElementById(idClicked).innerHTML = "X";
}
}
CheckAllEmpty('td1');
<table id="tb">
<tr>
<td id="td1" onclick="CheckAllEmpty(this.id)"></td>
<td id="td2"></td>
<td id="td3"></td>
</tr>
<tr>
<td id="td4"></td>
<td id="td5"></td>
<td id="td6"></td>
</tr>
<tr>
<td id="td7"></td>
<td id="td8"></td>
<td id="td9"></td>
</tr>
</table>
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 should I get an array value from a table cell when clicking checkbox with jQuery? If I've selected cell 1, I want to get array like ["BlackBerry Bold", "2/5", "UK"], but if I've selected all of them, I want to get all the data in the form of an array of arrays.
<table border="1">
<tr>
<th><input type="checkbox" /></th>
<th>Cell phone</th>
<th>Rating</th>
<th>Location</th>
</tr>
<tr>
<td align="center"><input type="checkbox"/></td>
<td>BlackBerry Bold 9650</td>
<td>2/5</td>
<td>UK</td>
</tr>
<tr>
<td align="center"><input type="checkbox" /></td>
<td>Samsung Galaxy</td>
<td>3.5/5</td>
<td>US</td>
</tr>
<tr>
<td align="center"><input type="checkbox"/></td>
<td>Droid X</td>
<td>4.5/5</td>
<td>REB</td>
</tr>
Please help.
Onclick get 3 children of the parent and add content to data. Used jquery nextAll for siblings and splice the 3 required.
Attached event to the table, onclick will check if element is INPUT.
If it's input, will get parent of that input which will be <td>.
For this parent element, will get three siblings using jquery.
Will add in selected if not present else delete, using indexOf.
CodePen for you to playaround: [ https://codepen.io/vivekamin/pen/oQMeXV ]
let selectedData = []
let para = document.getElementById("selectedData");
let tableElem = document.getElementById("table");
tableElem.addEventListener("click", function(e) {
if(e.target.tagName === 'INPUT' ){
let parent = e.target.parentNode;
let data = [];
$(parent).nextAll().map(function(index, node){
data.push(node.textContent);
})
let index = selectedData.indexOf(JSON.stringify(data))
if(index == -1){
selectedData.push(JSON.stringify(data));
}
else{
selectedData.splice(index,1);
}
para.textContent = "";
para.innerHTML = selectedData ;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table border="1" id="table">
<tr>
<th><input type="checkbox" /></th>
<th>Cell phone</th>
<th>Rating</th>
<th>Location</th>
</tr>
<tr>
<td align="center"><input type="checkbox"/></td>
<td>BlackBerry Bold 9650</td>
<td>2/5</td>
<td>UK</td>
</tr>
<tr>
<td align="center"><input type="checkbox" /></td>
<td>Samsung Galaxy</td>
<td>3.5/5</td>
<td>US</td>
</tr>
<tr>
<td align="center"><input type="checkbox"/></td>
<td>Droid X</td>
<td>4.5/5</td>
<td>REB</td>
</tr>
</table>
<h3> Selected Data: </h3>
<p id="selectedData"></p>
Updated to meet your needs.
create a function to build the array values based on looking for any checked inputs then going to their parents and grabbing the sibling text values
attach your change event to the checkbox click even.
I provided a fiddle below that will output the array in the console.
function buildTheArray(){
var thearray = [];
$("input:checked").parent().siblings().each(function(){
thearray.push($(this).text());
});
return thearray;
}
$("input[type='checkbox']").change(function(){
console.log(buildTheArray());
});
Fiddle:
http://jsfiddle.net/gcu4L5p6/
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>