I'm trying to convert table string (like csv) to html table.
My code works fine with simple table but when it merged row and column it fails. so how do i can use rowspan and column span in the script?
<!DOCTYPE html>
<html ng-app="" ng-controller="myCtrl">
<style>
table, th, td {
border: 1px solid black;
padding:5px;
}
table {
border-collapse: collapse;
margin:10px;
}
</style>
<body>
<button ng-click="processData(allText)">
Display CSV as Data Table
</button>
<div id="divID">
<table>
<tr ng-repeat="x in data">
<td ng-repeat="y in x">{{ y }}</td>
</tr>
</table>
</div>
<div>
<table>
</table>
</div>
JS
<script>
function myCtrl($scope, $http) {
$scope.allText="Series |Wire Range\n (AWG) |"+
"Wire Type |FW |Voltage\n (V) |Current \n (A) |"+
"UG |CA |\nSL-6100 RS#2|26 16, SOL,\n Unprepared |"+
"Cu RS#2|2 RS#2|300 RS#2|7 RS#2|B, D RS#2|"+
"2(105), 4 RS#2|\n24 - 16, STR,\n Unprepared |"+
"\nNominal Strip length: 9 - 10 mm CS#8|"+
"\nEnvironmental - Maximum ambient temperature"+
" rating for CNR: 85 C CS#8|\n";
$scope.processData = function(allText) {
// split content based on new line
var allTextLines = allText.split(/\|\n|\r\n/);
var headers = allTextLines[0].split('|');
var lines = [];
for ( var i = 0; i < allTextLines.length; i++) {
// split content based on comma
var data = allTextLines[i].split('|');
if (data.length == headers.length) {
var temp = [];
for ( var j = 0; j < headers.length; j++) {
temp.push(data[j]);
}
lines.push(temp);
}
};
$scope.data = lines;
};
}
</script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
</body>
</html>
RS#2 ---indicates rowspan of 2
cs#8 ---indicates colspan of 8
| ---is the dilimiter for cell
|\n ---for new line
and value in $scope.allText is CSV table string
so essentially i should get this table as output-
You can create an object with rows and cols so that you can use that as rowspan and colspan.
Like this
Demo
$scope.processData = function(allText) {
// split content based on new line
var allTextLines = allText.split(/\|\n|\r\n/);
var headers = allTextLines[0].split('|');
var lines = [];
var r,c;
for ( var i = 0; i < allTextLines.length; i++) {
// split content based on comma
var data = allTextLines[i].split('|');
if (data.length == headers.length) {
var temp = [];
for ( var j = 0; j < headers.length; j++) {
if(data[j].indexOf("RS") !== -1) {
r = data[j].split("#").reverse()[0];
}
else {
r = 0;
}
if(data[j].indexOf("CS") !== -1) {
c = data[j].split("#").reverse()[0];
}
else {
c = 0;
}
temp.push({"rows":r,"cols":c,"data":data[j]});
}
lines.push(temp);
}
}
alert(JSON.stringify(lines));
$scope.data = lines;
}
You can add CS to your string and alter conditions as required in this code.
Controller
function myCtrl($scope, $http) {
$scope.allText = "Series |Wire Range\n (AWG) |Wire Type |FW |Voltage\n (V) |Current \n (A) |UG |CA |\nSL-6100 RS#2|26 16, SOL,\n Unprepared |Cu RS#2|2 RS#2|300 RS#2|7 RS#2|B, D RS#2|2(105), 4 RS#2|\n24 - 16, STR,\n Unprepared |\nNominal Strip length: 9 - 10 mm CS#8|\nEnvironmental - Maximum ambient temperature rating for CNR: 85 C CS#8";
$scope.processData = function (allText) {
var table = [];
allText.split(/\|\n|\r\n/).forEach(function (line) {
var tr = [];
line.split('|').forEach(function (cell) {
tr.push({
text: cell.replace(/RS#.*$/, '').replace(/CS#.*$/, ''),
rowspan: (cell + 'RS#1').replace(/^[\S\s]*?RS#(\d*).*$/, '$1'),
colspan: (cell + 'CS#1').replace(/^[\S\s]*?CS#(\d*).*$/, '$1'),
})
})
table.push(tr)
});
$scope.table = table;
};
}
HTML
<table>
<tr ng-repeat="tr in table">
<td ng-repeat="td in tr" ng-attr-colspan="{{td.colspan}}" ng-attr-rowspan="{{td.rowspan}}">{{ td.text }}</td>
</tr>
</table>
Code Snippet
function myCtrl($scope, $http) {
$scope.allText = "Series |Wire Range\n (AWG) |Wire Type |FW |Voltage\n (V) |Current \n (A) |UG |CA |\nSL-6100 RS#2|26 16, SOL,\n Unprepared |Cu RS#2|2 RS#2|300 RS#2|7 RS#2|B, D RS#2|2(105), 4 RS#2|\n24 - 16, STR,\n Unprepared |\nNominal Strip length: 9 - 10 mm CS#8|\nEnvironmental - Maximum ambient temperature rating for CNR: 85 C CS#8";
$scope.processData = function (allText) {
var table = [];
allText.split(/\|\n|\r\n/).forEach(function (line) {
var tr = [];
line.split('|').forEach(function (cell) {
tr.push({
text: cell.replace(/RS#.*$/, '').replace(/CS#.*$/, ''),
rowspan: (cell + 'RS#1').replace(/^[\S\s]*?RS#(\d*).*$/, '$1'),
colspan: (cell + 'CS#1').replace(/^[\S\s]*?CS#(\d*).*$/, '$1'),
})
})
table.push(tr)
});
$scope.table = table;
};
}
angular.module('myApp', [])
.controller('ctrlr', myCtrl)
table, th, td {
border: 1px solid black;
padding: 5px;
}
table {
border-collapse: collapse;
margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="ctrlr">
<button ng-click="processData(allText)">
Display CSV as Data Table
</button>
<div id="divID">
<table>
<tr ng-repeat="tr in table">
<td ng-repeat="td in tr" ng-attr-colspan="{{td.colspan}}" ng-attr-rowspan="{{td.rowspan}}">{{ td.text }}</td>
</tr>
</table>
</div>
<div>
<table></table>
</div>
</div>
</div>
Related
Each time I input another football score, the league table is updated and displayed but it's appended to a list of tables. How do I display only the latest table?
Here is an extract of the html:
<div>
<table id="matches" border="1"> </table>
</div>
<div>
<table id="standings" border="1"> </table>
</div>
<input type="button" value="Update" onclick="update()" />
Here is the javascript that displays the fixtures for inputting scores:
// Display fixtures to input the scores
window.onload = function()
{
table = document.getElementById("matches");
var row;
var cell1;
var cell2;
var cell3;
for (i = 1; i < Results.length; i++)
{
row = table.insertRow(i-1); //table starts row 0 but Results row 1 so i-1 used
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell3 = row.insertCell(2);
cell4 = row.insertCell(3);
cell1.innerHTML = Results[i][0];
cell2.innerHTML = '<input type="number" min="0" max="99"/>'
cell3.innerHTML = '<input type="number" min="0" max="99"/>'
cell4.innerHTML = Results[i][3];
}
}
And here is the code that displays the table after the lastest scores have been inputed:
// Display League Table
standings = document.getElementById("standings");
for (i = 0; i < League.length; i++)
{
row = standings.insertRow(i);
cell1 = row.insertCell(0);
cell2 = row.insertCell(1);
cell3 = row.insertCell(2);
cell4 = row.insertCell(3);
cell5 = row.insertCell(4);
cell6 = row.insertCell(5);
cell7 = row.insertCell(6);
cell8 = row.insertCell(7);
cell1.innerHTML = League[i][0];
cell2.innerHTML = League[i][1];
cell3.innerHTML = League[i][2];
cell4.innerHTML = League[i][3];
cell5.innerHTML = League[i][4];
cell6.innerHTML = League[i][5];
cell7.innerHTML = League[i][6];
cell8.innerHTML = League[i][7];
}
After entering three scores this is what is displayed:
I've tried clearing the league array within javascript but still the same outcome. How do I only display top version of the table? Thanks
Thanks again to comments, and some further googling, the following deletes the table ahead of updating it, unless there's a better way?
for(var i = standings.rows.length - 1; i >= 0; i--)
{
standings.deleteRow(i);
}
Cheers everyone! :)
For your table update/question, focus on the updateRow function. This line does the actual update of contents of row rownum column(<td>) i
rows[rownum].getElementsByTagName('td')[i].innerHTML = coldata[i];
There is more here than just updating the table rows, for that you can review the function updateRow in my name-spaced object. updateRow calls createRow if it needs to (the row at that index does not exist), nothing fancy here, then updates the new row.
I use the array of match objects in matches I created (was not one in the question so I made assumptions) also in the namespace:
matches: [{
match: 1,
score: [{
team: "Ap",
score: 3
}, {
team: "Or",
score: 2
}]
}],
Note where I call this code to update the table for standings in the table with standings-table id. I have no idea what those are so I simply inserted some stuff in the array then update the table using
for (let i = 0; i < myLeague.standings.length; i++) {
myLeague.updateRow('standings-table', myLeague.standings[i], i);
}
Other things: I created the form simply to show how to update the table when a new match is inserted, I trigger an event and it does what it needs to update or insert a row - but really that is just to test the update as new matches are created.
Row in a table are either updated or inserted depending totally on the array of matches content
nothing handles deletions from the table or array since this was just about insert and update
if a row index for a match index does not exist, it creates a new row and updates it
var myLeague = myLeague || {
teamSelect1: "team1",
teamSelect2: "team2",
matchesPlayed: 1,
teams: [{
name: "Apples",
abbreviation: "Ap"
},
{
name: "Oranges",
abbreviation: "Or"
},
{
name: "Pears",
abbreviation: "Pe"
}
],
matches: [{
match: 1,
score: [{
team: "Ap",
score: 3
}, {
team: "Or",
score: 2
}]
}],
standings: [
["A", 2, 1, 1, 3, 2, 3, 0],
["B", 3, 1, 1, 3, 2, 3, 6]
],
cloneRow: function(tableid, objectRef) {
// find table to clone/append to
let table = document.getElementById(tableid);
// find row to clone, I use first one
let firstRow = mytable.rows[0];
// let row = document.getElementById("rowToClone");
let clone = firstRow.cloneNode(true); // copy children too
clone.id = ""; // change id or other attributes/contents
table.appendChild(clone); // add new row to end of table
},
createRow: function(tableid, colCount, rowCount = 1, defaultContent = "") {
let row = document.createElement('tr'); // create row node
for (let i = 0; i < colCount; i++) {
let newText = document.createTextNode(defaultContent);
let col = row.insertCell(i);
col.appendChild(newText);
}
let table = document.getElementById(tableid); // find table to append to
let tbody = table.getElementsByTagName('tbody')[0];
for (let r = 1; r <= rowCount; r++) {
tbody.appendChild(row); // append row to table
}
},
updateRow: function(tableid, coldata = ['$nbsp;'], rownum = 0) {
let table = document.getElementById(tableid); // find table to update to
let tbody = table.getElementsByTagName('tbody')[0];
let rows = tbody.rows; // get rows node
let maxRows = 20; //keep it from going crazy adding rows
while (rows.length < maxRows && !rows[rownum]) {
this.createRow(tableid, coldata.length, 1, "x");
}
//myLeague.updateRow(tableid,coldata, rownum);
for (let i = 0; i < coldata.length; i++) {
rows[rownum].getElementsByTagName('td')[i].innerHTML = coldata[i];
}
},
addTeam: function(team, teamid) {
var sel = document.getElementById(teamid);
var optNew = document.createElement("option");
optNew.value = team.abbreviation;
optNew.text = team.name;
sel.add(optNew, null);
},
addTeamsToSelect: function() {
myLeague.teams.forEach(function(team) {
myLeague.addTeam(team, this.teamSelect1);
myLeague.addTeam(team, this.teamSelect2);
}, this);
},
listMatches: function(event) {
// event.target is the div
let src = event.target.dataset.source;
console.log("src:", src);
document.getElementById("matchplayed").textContent = event.matches;
this[src].forEach(function(item, index, array) {
document.getElementById('matchplayed').textContent = array.length;
let rowdata = [item.score[0].team, item.score[0].score, item.score[1].team, item.score[1].score];
this.updateRow(src, rowdata, index);
}, this);
},
clickAddListener: function(event) {
// 'this' is bound to the namespace object
// console.log(event.target); // the button
// console.log(this.matchesPlayed);//namespace
if (!document.getElementById(this.teamSelect1).value || !document.getElementById(this.teamSelect2).value) {
let errorEl = document.getElementById("form1")
.getElementsByClassName("error-text")[0];
errorEl.textContent = "Both teams need to be selected.";
errorEl.style.visibility = 'visible';
errorEl.style.opacity = '1';
setTimeout(function() {
errorEl.style.WebkitTransition = 'visibility .5s, opacity .5s';
errorEl.style.opacity = '0';
errorEl.style.visibility = 'hidden';
errorEl.textContent = "";
}, 5000);
} else {
this.matchesPlayed++;
let r = {
match: this.matchesPlayed,
score: [{
team: document.getElementById(this.teamSelect1).value,
score: document.getElementById("score1").value
}, {
team: document.getElementById(this.teamSelect2).value,
score: document.getElementById("score2").value
}]
};
this.matches.push(r);
}
document.getElementById('matches').dispatchEvent(this.showmatchesevent);
},
addListeners: function() {
let scope = this;
document.getElementById(this.teamSelect1)
.addEventListener('change', function() {
let s = document.getElementById(scope.teamSelect2);
let oval = s.value;
if (this.value == oval) {
s.value = '';
}
}, this);
document.getElementById(this.teamSelect2)
.addEventListener('change', function() {
let s = document.getElementById(scope.teamSelect1);
let oval = s.value;
if (this.value == oval) {
s.value = '';
}
}, this);
document.getElementById('add-match')
// bind this namespace to the event listener function
.addEventListener('click', (this.clickAddListener).bind(this), false);
this.showmatchesevent = new CustomEvent('showmatches');
document.getElementById('matches')
.addEventListener('showmatches', this.listMatches.bind(this), false);
}
};
window.onload = function() {
myLeague.addTeamsToSelect();
myLeague.addListeners();
for (let i = 0; i < myLeague.standings.length; i++) {
myLeague.updateRow('standings-table', myLeague.standings[i], i);
}
// set table from defaults/imported list
document.getElementById('matches').dispatchEvent(myLeague.showmatchesevent);
};
/* typography */
html {
font-family: 'helvetica neue', helvetica, arial, sans-serif;
}
th {
letter-spacing: 2px;
}
td {
letter-spacing: 1px;
}
tbody td {
text-align: center;
}
.match-inputs {
border: solid 2px #DDDDDD;
padding;
1em;
margin: 1em;
}
.error-text {
height: 1em;
color: red;
}
.matches-played {
padding: 13m;
}
/* table layout */
table {
border-collapse: collapse;
border: 1px solid black;
}
.score th,
td {
padding: 0.2em;
border: solid #DDDDDD 1px;
}
.container {
padding: 1em;
}
<div class="container match-inputs">
<form id="form1">
<div>Add Matches</div>
<div class="input-group"><label>Choose L Team:</label>
<select id="team1">
<option value="">Choose</option>
</select>
</div>
<div class="input-group"><label>Choose L2 Team:</label>
<select id="team2">
<option value="">Choose</option>
</select>
</div>
<div class="input-group score-group"><label>Team1 score:</label>
<input id="score1" type="number" class="score-input" value="0" min="0" max="99" value="0" />
</div>
<div class="input-group score-group"><label>Team2 score:</label>
<input id="score2" type="number" class="score-input" value="0" min="0" max="99" value="0" />
</div>
<div class="input-group"><label>Add this match to the list.</label>
<button type="button" id="add-match">Add Match</button>
</div>
<div class="error-text"> </div>
</form>
</div>
<div class="container">
<div class="matches-played">Matches Played:<span id="matchplayed"></span></div>
<table id="matches" data-source="matches">
<thead>
<tr>
<th colspan="4">Matches</th>
</tr>
<tr>
<th>L</th>
<th>S</th>
<th>S2</th>
<th>L1</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="container">
<table id="standings-table">
<thead>
<tr>
<th colspan="8">Standings</th>
</tr>
<tr>
<th>Team</th>
<th>P</th>
<th>W</th>
<th>D</th>
<th>L</th>
<th>F</th>
<th>A</th>
<th>Pts</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
I have a table with 5 columns. the following code will filter the data on basis of all columns. I want to filter the data for each column. for ex: if there are 10 columns then 10 search fields and Also how can I make HTML part Dynamic so that I don't have to add one more search text field whenever a new column is added.
<input id="myInput" type="text" />
<script>
function filterTable(event) {
var filter = event.target.value.toUpperCase();
var rows = document.querySelector("#myTable tbody").rows;
for (var i = 1; i < rows.length; i++) {
var Col1 = rows[i].cells[0].textContent.toUpperCase();
var Col2 = rows[i].cells[1].textContent.toUpperCase();
var Col3 = rows[i].cells[2].textContent.toUpperCase();
var Col4 = rows[i].cells[3].textContent.toUpperCase();
var Col5 = rows[i].cells[4].textContent.toUpperCase();
if (Col1.indexOf(filter) > -1 || Col2.indexOf(filter) > -1 || Col3.indexOf(filter) > -1
|| Col4.indexOf(filter) > -1 || Col5.indexOf(filter) > -1) {
rows[i].style.display = "";
} else {
rows[i].style.display = "none";
}
}
}
document.querySelector(''#myInput'').addEventListener(''keyup'', filterTable, false);
</script>
I want to have this kind of functionality:
You can loop over the rows and then the columns. The Array.from method allows you to cast an element list to an array so that you can iterate over the children with Array.prototype.forEach.
All you need to do is have a show initialized to true for each row. Then if any DOES NOT column meets the filter criteria, you set show to false. After looping through all columns you display the row based on the final value of show.
Edit: Make sure you are using a browser that supports ES6+. There is a polyfill available for Array.from on the MDN site.
function filterTable(event) {
let filter = event.target.value.trim().toLowerCase();
let rows = document.querySelector('#myTable tbody').rows;
for (let i = 0; i < rows.length; i++) {
let row = rows[i], show = false;
if (filter.length > 0) {
for (let j = 0; j < row.children.length; j++) {
let col = row.children[j], text = col.textContent.toLowerCase();
if (text.indexOf(filter) > -1) {
show = true;
continue;
}
}
} else {
show = true;
}
// Avoid using 'row.styledisplay' - https://stackoverflow.com/a/28028656/1762224
// Avoid using 'row.visibility' - rows do not collapse
toggleClass(row, 'hidden-row', !show);
}
}
function toggleClass(el, className, state) {
if (el.classList) el.classList.toggle(className, state);
else {
var classes = el.className.split(' ');
var existingIndex = classes.indexOf(className);
if (state === undefined) {
if (existingIndex > -1) classes.splice(existingIndex, 1)
else classes.push(existingIndex);
} else {
if (!state) classes.splice(existingIndex, 1)
else classes.push(existingIndex);
}
el.className = classes.join(' ');
}
}
document.querySelector('#myInput').addEventListener('keyup', filterTable, false);
body {
padding: 8px;
}
.field label {
font-weight: bold;
margin-right: 0.25em;
}
#myTable {
margin-top: 0.667em;
width: 100%;
}
#myTable th {
text-transform: capitalize;
}
.hidden-row {
display: none;
}
<link href="https://unpkg.com/purecss#1.0.0/build/pure-min.css" rel="stylesheet" />
<div class="field"><label for="myInput">Filter:</label><input id="myInput" type="text" /></div>
<table id="myTable" class="pure-table pure-table-horizontal">
<thead>
<tr>
<th>name</th>
<th>drink</th>
<th>pizza</th>
<th>movie</th>
</tr>
</thead>
<tbody>
<tr>
<td>Homer</td>
<td>Squishie</td>
<td>Magheritta</td>
<td>The Avengers</td>
</tr>
<tr>
<td>Marge</td>
<td>Squishie</td>
<td>Magheritta</td>
<td>The Avengers</td>
</tr>
<tr>
<td>Bart</td>
<td>Squishie</td>
<td>Pepperoni</td>
<td>Black Dynamite</td>
</tr>
<tr>
<td>Lisa</td>
<td>Buzz Cola</td>
<td>Pepperoni</td>
<td>Iron Man</td>
</tr>
<tr>
<td>Maggie</td>
<td>Duff Beer</td>
<td>Magheritta</td>
<td>The Avengers</td>
</tr>
<tr>
<td>Kent</td>
<td>Duff Beer</td>
<td>Hawaiian</td>
<td>The Avengers</td>
</tr>
</tbody>
</table>
Search fields example
populateTable(document.getElementById('simpsons'), getData());
function dataFields(data) {
return data.reduce((r, x) => Object.keys(x).reduce((s, k) => s.indexOf(k) === -1 ? s.concat(k) : s, r), []);
}
/* Can be useful if working with raw JSON data */
function searchCriteria(fields) {
return Array.from(fields).reduce((o, field) => {
return Object.assign(o, { [field.getAttribute('placeholder')] : field.value });
}, {});
}
function onFilter(e) {
let table = e.target.parentElement.parentElement.parentElement.parentElement;
let fields = table.querySelectorAll('thead tr th input');
let criteria = searchCriteria(fields); // Unused, but useful if filtering bindable data
let searchText = Array.from(fields).map(field => field.value.trim());
Array.from(table.querySelectorAll('tbody tr')).forEach(row => {
let hideRow = false;
Array.from(row.children).forEach((col, index) => {
var value = col.innerHTML.trim().toLowerCase();
var search = searchText[index].toLowerCase();
if (search.length > 0) {
if (!value.startsWith(search)) { /* or value.indexOf(search) === -1 */
hideRow = true;
return;
}
}
});
row.classList.toggle('hidden-row', hideRow);
});
}
function populateTable(table, data) {
let fields = dataFields(data);
let thead = document.createElement('THEAD');
let tr = document.createElement('TR');
fields.forEach(field => {
let th = document.createElement('TH');
th.innerHTML = field;
tr.appendChild(th);
});
thead.appendChild(tr);
let tbody = document.createElement('TBODY');
tr = document.createElement('TR');
fields.forEach(field => {
let th = document.createElement('TH');
let input = document.createElement('INPUT');
input.setAttribute('placeholder', field);
input.addEventListener('keyup', onFilter);
th.append(input);
tr.appendChild(th);
});
thead.appendChild(tr);
data.forEach(record => {
let tr = document.createElement('TR');
fields.forEach(field => {
let td = document.createElement('TD');
td.innerHTML = record[field];
tr.appendChild(td);
});
tbody.append(tr);
});
table.appendChild(thead);
table.appendChild(tbody);
}
function getData() {
return [{
"name": "Homer",
"drink": "Squishie",
"pizza": "Magheritta",
"movie": "The Avengers"
}, {
"name": "Marge",
"drink": "Squishie",
"pizza": "Magheritta",
"movie": "The Avengers"
}, {
"name": "Bart",
"drink": "Squishie",
"pizza": "Pepperoni",
"movie": "Black Dynamite"
}, {
"name": "Lisa",
"drink": "Buzz Cola",
"pizza": "Pepperoni",
"movie": "Iron Man"
}, {
"name": "Maggie",
"drink": "Duff Beer",
"pizza": "Magheritta",
"movie": "The Avengers"
}, {
"name": "Kent",
"drink": "Duff Beer",
"pizza": "Hawaiian",
"movie": "The Avengers"
}];
}
table {
border-collapse: collapse;
width: 100%;
}
table thead tr th {
text-transform: capitalize;
}
table thead tr:last-child {
background: #eaeaea;
border-bottom: 4px double #cbcbcb;
}
table thead tr th input {
width: 100%;
}
table tbody tr:nth-child(even) {
background-color: #f2f2f2;
}
table tbody tr.hidden-row {
display: none;
}
<link href="https://unpkg.com/purecss#1.0.0/build/pure-min.css" rel="stylesheet" />
<table id="simpsons" class="pure-table pure-table-horizontal"></table>
Browser Compatibility
function onFilter(e) {
var table = e.target.parentElement.parentElement.parentElement.parentElement;
console.log(table);
var fields = table.querySelectorAll('thead tr th input');
console.log(fields);
var searchText = Array.from(fields).map(function (field) {
return field.value.trim();
});
console.log(searchText);
Array.from(table.querySelectorAll('tbody tr')).forEach(function (row) {
var hideRow = false;
Array.from(row.children).forEach(function (col, index) {
var value = col.innerHTML.trim().toLowerCase();
console.log(value);
var search = searchText[index].toLowerCase();
console.log(search);
if (search.length > 0) {
if (value.indexOf(search) === -1) {
hideRow = true;
return;
}
}
});
row.classList.toggle('hidden-row', hideRow);
});
}
All you have to do is iterate the .cells array with a for loop:
For this example, I used a variable to determine if the row should be shown.
function filterTable(event) {
var filter = event.target.value.toUpperCase();
var rows = document.querySelector("#myTable tbody").rows;
for (var i = 1; i < rows.length; i++) {
// Placeholder to indicate if a row matches the given query.
var shouldShowRow = false;
// Loop over all the cells in this row.
for (var k = 0; k < rows[i].cells.length) {
// Check to see if this cell in this row matches the query.
if (rows[i].cells[k].textContent.toUpperCase().indexOf(filter) > -1) {
// Yes, this cell matches, therefore this entire row matches.
// Flip the show row boolean to indicate that we need to show.
shouldShowRow = true;
// Because this cell matches, we do not need to check any more cells.
break;
}
}
// Change the display on the row if we need to.
if (shouldShowRow) {
rows[i].style.display = "";
} else rows[i].style.display = "none";
}
}
You can use array.
First map col to an array colArr and than using some you can match you can match filter content with content of cols .
for (var i = 1; i < rows.length; i++) {
let colArr = new Array(5).fill(0).map((e,index)=> rows[i].cells[index].textContent.toUpperCase();)
if (colArr.some(e=> e.indexOf(filter) > -1 ) {
rows[i].style.display = "";
} else {
rows[i].style.display = "none";
}
})
}
I am trying to make an annotation tool, where I will select some words and get their relative start and indices in the sentence.
I am using jQuery UI's selectable tool to select word(s) and get their data attributes out of them.
In this example, I want to select the splitted word(s): (HELLO, ,, WORLD, .) and get their data attributes out of them.
My hierarchy of div(s) is as follows:
#tblText > tbody > tr > td > #0 > div#div0.uiselectee.ui-selected
$(function() {
$('#btnAddUtterance').click(function() {
populateUtterance();
});
var selected1 = new Array();
$(".tokenized").selectable({
selected: function(event, ui) {
debugger;
alert(ui.selected.innerHTML);
selected1.push(ui.selected.id);
},
unselected: function(event, ui) {
//ui.unselected.id
}
});
var uttIdx = 0;
var tokenizedUtterances = new Array();
function populateUtterance() {
let userUtterance = $('#myInput').val();
let tokenizedUtterance = tokenizeUtterance(userUtterance, uttIdx);
let markup = `<tr><td><input type='checkbox' name='record'></td><td> ${tokenizedUtterance} </td> <td>${userUtterance}</td></tr>`;
$("#tblText tbody").append(markup);
uttIdx += 1;
$('#myInput').val('');
}
$("#myInput").keyup(function(event) {
if (event.keyCode === 13) {
populateUtterance();
}
});
function findSpacesIndex(utterance) {
let index = 0;
let spacesIndex = [];
while ((index = utterance.indexOf(' ', index + 1)) > 0) {
spacesIndex.push(index);
}
return spacesIndex;
}
function createUtteranceLookup(utterance) {
let lookUpObject = new Array();
utterance.replace(/[\w'-]+|[^\w\s]+/g, (word, offset) =>
lookUpObject.push({
word: word,
start: offset,
end: offset + word.length
}));
return lookUpObject;
}
function tokenizeUtterance(utterance) {
let div = `<div id=${uttIdx} class ='tokenizedUtterance'>`;
let spacesIndex = new Array();
spacesIndex = findSpacesIndex(utterance);
let utteranceLookup = new Array();
for (let i = 0; i < spacesIndex.length; i++) {
utteranceLookup.push({
word: " ",
start: spacesIndex[i],
end: spacesIndex[i]
});
}
let wordsIndex = [];
wordsIndex = createUtteranceLookup(utterance);
Array.prototype.push.apply(utteranceLookup, wordsIndex);
utteranceLookup.sort(function(obj1, obj2) {
return obj1.start - obj2.start;
});
for (let i = 0; i < utteranceLookup.length; i++)
utteranceLookup[i]["wordIndexInSentence"] = i;
$.each(wordsIndex, function(index, item) {
let divId = "div" + index;
let divStart = item.start;
let divEnd = item.end;
let divValue = item.word;
div += `<div style="display:inline-block;margin:5px; border: 1px solid black;" id = "${divId}" data-start=${divStart} data-end= ${divEnd} data-value= "${divValue}"> ${item.word} </div >`;
});
tokenizedUtterances.push({
UtteranceNumber: uttIdx,
tokenizedUtteranceLookup: utteranceLookup
});
div += '</div>';
$('#testOutput').html('');
$('#testOutput').html(JSON.stringify(tokenizedUtterances, undefined, 2));
utteranceLookup = new Array();
return div;
}
$(document).on("click", '#tblText > tbody > tr > td:nth-child(2)', function(event) {
//if ctrl key or left click is pressed, select tokenized word
if (event.ctrlKey || event.which === 1) {
$('.tokenizedUtterance').selectable();
}
console.log("Selected");
});
// Find and remove selected table rows
$(document).on('click', '#btnDeleteRow', function(e) {
$("#tblText tbody").find('input[name="record"]').each(function() {
if ($(this).is(":checked")) {
$(this).parents("tr").remove();
$('#testOutput').html('');
}
});
});
});
.tokenizedUtterance .ui-selecting {
background: #FFFF99;
}
.tokenizedUtterance .ui-selected {
background: #FFFF00;
font-family: 'Segoe UI';
font-style: italic
}
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<h2>AnnotationView</h2>
<h2>Enter text to annotate</h2>
<input type="text" id="myInput" />
<button id="btnAddUtterance" class="btn btn-info">Add Utterance</button>
<table id="tblText" class="table table-hover">
<thead>
<tr>
<th>Select</th>
<th>Tokenized User Utterance</th>
<th>Original Utterance</th>
</tr>
</thead>
<tbody></tbody>
</table>
<button id='btnDeleteRow' class='btn btn-danger'>Delete Utterance</button>
<span>You've selected:</span> <span id="select-result"></span>.
<hr />
<h1>Output is: </h1> <br />
<pre id="testOutput" style="word-wrap: break-word; white-space: pre-wrap;"></pre>
Here's a Fiddle of the app
Any help will be greatly appreciated.
I believe this is what you are looking for - PEN
We can make use of the selected and unselecting events in the Selectable Widget.
The selected elements are stored in a variable elem. Hope you can use this variable to access the data variables and construct the JSON. Please let me know whether this helps.
I have been trying to solve this for days.I would greatly appreciate any help you can give me in solving this problem. I have a table like the following:
ID Name Study
1111 Angela XRAY
2222 Bena Ultrasound
3333 Luis CT Scan
1111 Angela Ultrasound
3333 Luis XRAY
3333 Luis LASER
and I want to group them like:
ID Name Study
GROUP BY id(1111) 2 hits "+"
2222 Bena Ultrasound
GROUP BY id(3333) 3 hits "+"
AND if "+" is clicked then it will expand:
ID Name Study
GROUP BY id(1111) 2 hits "-"
1111 Angela XRAY
1111 Angela Ultrasound
2222 Bena Ultrasound
GROUP BY id(3333) 3 hits "-"
3333 Luis CT Scan
3333 Luis Ultrasound
3333 Luis LASER
There is a demo that I found on stackoverflow(http://jsfiddle.net/FNvsQ/1/) but the only problem I have is I want to include all rows having the same id under a dynamic header like
grouped by id(1111) then the expand/collapse icon (+/-)
var table = $('table')[0];
var rowGroups = {};
//loop through the rows excluding the first row (the header row)
while(table.rows.length > 0){
var row = table.rows[0];
var id = $(row.cells[0]).text();
if(!rowGroups[id]) rowGroups[id] = [];
if(rowGroups[id].length > 0){
row.className = 'subrow';
$(row).slideUp();
}
rowGroups[id].push(row);
table.deleteRow(0);
}
//loop through the row groups to build the new table content
for(var id in rowGroups){
var group = rowGroups[id];
for(var j = 0; j < group.length; j++){
var row = group[j];
if(group.length > 1 && j == 0) {
//add + button
var lastCell = row.cells[row.cells.length - 1];
$("<span class='collapsed'>").appendTo(lastCell).click(plusClick);
}
table.tBodies[0].appendChild(row);
}
}
//function handling button click
function plusClick(e){
var collapsed = $(this).hasClass('collapsed');
var fontSize = collapsed ? 14 : 0;
$(this).closest('tr').nextUntil(':not(.subrow)').slideToggle(400)
.css('font-size', fontSize);
$(this).toggleClass('collapsed');
}
Here is the answer to my own question.
First id's are added to the table and the rows and there's a small change to the JS:
var table = $('table')[0];
var rowGroups = {};
//loop through the rows excluding the first row (the header row)
while (table.rows.length > 1) {
var row = table.rows[1];
var id = $(row.cells[0]).text();
if (!rowGroups[id]) rowGroups[id] = [];
if (rowGroups[id].length > 0) {
row.className = 'subrow';
$(row).slideUp();
}
rowGroups[id].push(row);
table.deleteRow(1);
}
//loop through the row groups to build the new table content
for (var id in rowGroups) {
var group = rowGroups[id];
for (var j = 0; j < group.length; j++) {
var row = group[j];
var notSubrow = false;
if (group.length > 1 && j == 0) {
//add + button
var lastCell = row.cells[row.cells.length - 1];
var rowId = row.id;
var tableId = table.id;
notSubrow = true;
//$("<span class='collapsed'>").appendTo(lastCell).click(plusClick);
}
table.tBodies[0].appendChild(row);
if (notSubrow) {
$('#' + tableId).find('#' + rowId).attr('class', 'subrow');
$('#' + tableId).find('#' + rowId).before("<tr class='subrowHeader' style='background:#E6E6FA;border-bottom:1px solid #708AA0 !important'><td colspan='3'> group by " + $(row.cells[0]).text() + " (" + group.length + ")" + "<span class='collapsed' onclick='plusClick(this)' style='float:left;display:inline'></td></tr>");
$('#' + tableId).find('#' + rowId).hide();
}
}
}
//function handling button click
function plusClick(e) {
var collapsed = $(e).hasClass('collapsed');
var fontSize = collapsed ? 14 : 0;
$(e).closest('tr').nextUntil(':not(.subrow)').slideToggle('fast').css('font-size', fontSize);
$(e).toggleClass('collapsed');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="table1">
<tr id="tr1">
<th>Parent ID</th>
<th>Parent Name</th>
<th>Study</th>
</tr>
<tr id="tr2">
<td>1111</td>
<td>Angela</td>
<td>XRAY</td>
</tr>
<tr id="tr3">
<td>2222</td>
<td>Bena</td>
<td>Untrasound</td>
</tr>
<tr id="tr4">
<td>3333</td>
<td>Luis</td>
<td>CT Scan</td>
</tr>
<tr id="tr5">
<td>1111</td>
<td>Angela</td>
<td>Untrasound</td>
</tr>
<tr id="tr6">
<td>3333</td>
<td>Luis</td>
<td>LCD</td>
</tr>
<tr id="tr7">
<td>3333</td>
<td>Luis</td>
<td>LASER</td>
</tr>
</table>
*Inorder to test copy and paste the code into http://jsfiddle.net/FNvsQ/1/ &
In the Frameworks & Extensions panel, set onLoad to No wrap - in body.
As a comparison, here's a POJS function that is functionally equivalent in the same amount of code. Doesn't use a large external library though.
It uses the same algorithm of collecting all rows with the same value in the first cell, then modifies the table to insert header rows and group the data rows.
// Group table rows by first cell value. Assume first row is header row
function groupByFirst(table) {
// Add expand/collapse button
function addButton(cell) {
var button = cell.appendChild(document.createElement('button'));
button.className = 'toggleButton';
button.textContent = '+';
button.addEventListener('click', toggleHidden, false);
return button;
}
// Expand/collapse all rows below this one until next header reached
function toggleHidden(evt) {
var row = this.parentNode.parentNode.nextSibling;
while (row && !row.classList.contains('groupHeader')) {
row.classList.toggle('hiddenRow');
row = row.nextSibling;
}
}
// Use tBody to avoid Safari bug (appends rows to table outside tbody)
var tbody = table.tBodies[0];
// Get rows as an array, exclude first row
var rows = Array.from(tbody.rows).slice(1);
// Group rows in object using first cell value
var groups = rows.reduce(function(groups, row) {
var val = row.cells[0].textContent;
if (!groups[val]) groups[val] = [];
groups[val].push(row);
return groups;
}, Object.create(null));
// Put rows in table with extra header row for each group
Object.keys(groups).forEach(function(value, i) {
// Add header row
var row = tbody.insertRow();
row.className = 'groupHeader';
var cell = row.appendChild(document.createElement('td'));
cell.colSpan = groups[value][0].cells.length;
cell.appendChild(
document.createTextNode(
'Grouped by ' + table.rows[0].cells[0].textContent +
' (' + value + ') ' + groups[value].length + ' hits'
)
);
var button = addButton(cell);
// Put the group's rows in tbody after header
groups[value].forEach(function(row){tbody.appendChild(row)});
// Call listener to collapse group
button.click();
});
}
window.onload = function(){
groupByFirst(document.getElementById('table1'));
}
table {
border-collapse: collapse;
border-left: 1px solid #bbbbbb;
border-top: 1px solid #bbbbbb;
}
th, td {
border-right: 1px solid #bbbbbb;
border-bottom: 1px solid #bbbbbb;
}
.toggleButton {
float: right;
}
.hiddenRow {
display: none;
}
<table id="table1">
<tr id="tr1">
<th>Parent ID</th>
<th>Parent Name</th>
<th>Study</th>
</tr>
<tr id="tr2">
<td>1111</td>
<td>Angela</td>
<td>XRAY</td>
</tr>
<tr id="tr3">
<td>2222</td>
<td>Bena</td>
<td>Ultrasound</td>
</tr>
<tr id="tr4">
<td>3333</td>
<td>Luis</td>
<td>CT Scan</td>
</tr>
<tr id="tr5">
<td>1111</td>
<td>Angela</td>
<td>Ultrasound</td>
</tr>
<tr id="tr6">
<td>3333</td>
<td>Luis</td>
<td>LCD</td>
</tr>
<tr id="tr7">
<td>3333</td>
<td>Luis</td>
<td>LASER</td>
</tr>
</table>
I am trying to insert multiple rows and columns to create a table in html dynamically by selecting the number of rows and columns in dropdown list using javascript code like in MS Word.
For example if I select number of rows as 5 and number of columns as 5 from the dropdown list of numbers. 5 rows and 5 columns should get displayed.
My question is how can I add multiple rows and columns dynamically to create a table by selecting the number of rows and columns from the drop down list.
Since, <table> element is the one of the most complex structures in HTML, HTML DOM provide new interface HTMLTableElement with special properties and methods for manipulating the layout and presentation of tables in an HTML document.
So, if you want to accomplish expected result using DOM standards you can use something like this:
Demo old
Demo new
HTML:
<ul>
<li>
<label for="column">Add a Column</label>
<input type="number" id="column" />
</li>
<li>
<label for="row">Add a Row</label>
<input type="number" id="row" />
</li>
<li>
<input type="button" value="Generate" id="btnGen" />
<input type="button" value="Copy to Clipboard" id="copy" />
</li>
</ul>
<div id="wrap"></div>
JS new:
JavaScript was improved.
(function (window, document, undefined) {
"use strict";
var wrap = document.getElementById("wrap"),
setColumn = document.getElementById("column"),
setRow = document.getElementById("row"),
btnGen = document.getElementById("btnGen"),
btnCopy = document.getElementById("btnCopy");
btnGen.addEventListener("click", generateTable);
btnCopy.addEventListener("click", copyTo);
function generateTable(e) {
var newTable = document.createElement("table"),
tBody = newTable.createTBody(),
nOfColumns = parseInt(setColumn.value, 10),
nOfRows = parseInt(setRow.value, 10),
row = generateRow(nOfColumns);
newTable.createCaption().appendChild(document.createTextNode("Generated Table"));
for (var i = 0; i < nOfRows; i++) {
tBody.appendChild(row.cloneNode(true));
}
(wrap.hasChildNodes() ? wrap.replaceChild : wrap.appendChild).call(wrap, newTable, wrap.children[0]);
}
function generateRow(n) {
var row = document.createElement("tr"),
text = document.createTextNode("cell");
for (var i = 0; i < n; i++) {
row.insertCell().appendChild(text.cloneNode(true));
}
return row.cloneNode(true);
}
function copyTo(e) {
prompt("Copy to clipboard: Ctrl+C, Enter", wrap.innerHTML);
}
}(window, window.document));
JS old:
(function () {
"use strict";
var wrap = document.getElementById("wrap"),
setColumn = document.getElementById("column"),
setRow = document.getElementById("row"),
btnGen = document.getElementById("btnGen"),
copy = document.getElementById("copy"),
nOfColumns = -1,
nOfRows = -1;
btnGen.addEventListener("click", generateTable);
copy.addEventListener("click", copyTo);
function generateTable(e) {
var newTable = document.createElement("table"),
caption = newTable.createCaption(),
//tHead = newTable.createTHead(),
//tFoot = newTable.createTFoot(),
tBody = newTable.createTBody();
nOfColumns = parseInt(setColumn.value, 10);
nOfRows = parseInt(setRow.value, 10);
caption.appendChild(document.createTextNode("Generated Table"));
// appendRows(tHead, 1);
// appendRows(tFoot, 1);
appendRows(tBody);
(wrap.hasChildNodes() ? wrap.replaceChild : wrap.appendChild).call(wrap, newTable, wrap.firstElementChild);
}
function appendColumns(tElement, count) {
var cell = null,
indexOfRow = [].indexOf.call(tElement.parentNode.rows, tElement) + 1,
indexOfColumn = -1;
count = count || nOfColumns;
for (var i = 0; i < count; i++) {
cell = tElement.insertCell(i);
indexOfColumn = [].indexOf.call(tElement.cells, cell) + 1;
cell.appendChild(document.createTextNode("Cell " + indexOfColumn + "," + indexOfRow));
}
}
function appendRows(tElement, count) {
var row = null;
count = count || nOfRows;
for (var i = 0; i < count; i++) {
row = tElement.insertRow(i);
appendColumns(row);
}
}
function copyTo(e) {
prompt("Copy to clipboard: Ctrl+C, Enter", wrap.innerHTML);
}
}());
If you want to copy generated result to clipboard you can look at answer of Jarek Milewski - How to copy to the clipboard in JavaScript?
You can use this function to generate dynamic table with no of rows and cols you want:
function createTable() {
var a, b, tableEle, rowEle, colEle;
var myTableDiv = document.getElementById("DynamicTable");
a = document.getElementById('txtRows').value; //No of rows you want
b = document.getElementById('txtColumns').value; //No of column you want
if (a == "" || b == "") {
alert("Please enter some numeric value");
} else {
tableEle = document.createElement('table');
for (var i = 0; i < a; i++) {
rowEle = document.createElement('tr');
for (var j = 0; j < b; j++) {
colEle = document.createElement('td');
rowEle.appendChild(colEle);
}
tableEle.appendChild(rowEle);
}
$(myTableDiv).html(tableEle);
}
}
Try something like this:
var
tds = '<td>Data'.repeat(col_cnt),
trs = ('<tr>'+tds).repeat(row_cnt),
table = '<table>' + trs + '</table>;
Then place the table in your container:
document.getElementById('tablePreviewArea').innerHTML = table;
Or with JQuery:
$('#tablePreviewArea').html(table);
Here is the JSFiddle using native js.
Here is the JSFiddle using jQuery.
About the string repeat function
I got the repeat function from here:
String.prototype.repeat = function( num )
{
return new Array( num + 1 ).join( this );
}
I had one sample code...try this and modify it according to your requirement. May it helps you out.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<style type="text/css">
#mytab td{
width:100px;
height:20px;
background:#cccccc;
}
</style>
<script type="text/javascript">
function addRow(){
var root=document.getElementById('mytab').getElementsByTagName('tbody')[0];
var rows=root.getElementsByTagName('tr');
var clone=cloneEl(rows[rows.length-1]);
root.appendChild(clone);
}
function addColumn(){
var rows=document.getElementById('mytab').getElementsByTagName('tr'), i=0, r, c, clone;
while(r=rows[i++]){
c=r.getElementsByTagName('td');
clone=cloneEl(c[c.length-1]);
c[0].parentNode.appendChild(clone);
}
}
function cloneEl(el){
var clo=el.cloneNode(true);
return clo;
}
</script>
</head>
<body>
<form action="">
<input type="button" value="Add a Row" onclick="addRow()">
<input type="button" value="Add a Column" onclick="addColumn()">
</form>
<br>
<table id="mytab" border="1" cellspacing="0" cellpadding="0">
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
</table>
</body>
</html>
Instead of button , you can use select menu and pass the value to variable. It will create row ,column as per the value.