Javascript-Collapsing and expanding table rows based on hierarchy - javascript

I have the following table generated by a cgi script:
<table>
<tr id='vfipbb'><td>col 1,0</td><td>col 1,1</td></tr>
<tr id='vfipbb.alipbb'><td>col 2,0</td><td>col 2,1</td></tr>
<tr id='vfipbb.esipbb'><td>col 3,0</td><td>col 3,1</td></tr>
<tr id='vfipbb.esipbb.esipbb_madrid'><td>col 4,0</td><td>col 4,1</td></tr>
<tr id='vfipbb.esipbb.esipbb_barcelona'><td>col 5,0</td><td>col 5,1</td></tr>
</table>
This is just a sample of what it would look like, but the important bit to note is the id.
when the webpage first loads all rows are collapsed except for the root context (vfipbb). I want to enable functionality when the root context is clicked it will expand all child rows listed under this, for example (alipbb), (esipbb) and if one of the child rows is clicked it will expand all grandchildren rows, for example (esipbb_madrid) (esipbb_barcelona).
Is there any efficient way of doing this in javascript based on ID? Any pointer in the right direction would be greatly welcome!

Not a working code, but something to get you started
// add click handlers to all tr
var tr0 = document.getElementsByTagName("tr");
for (var i = 0; i < tr0.length; i++) {
tr0[i].addEventListener("click", openChild);
}
function openChild() {
var id = this.id;
//regex that matches a string beginning with
//the id followed by dot and some other words
var regex = new RegExp("^" + id + ".[a-z_]+$", "g");
var tr1 = document.getElementsByTagName("tr");
//browse through the tr(s)
for (var i = 0; i < tr1.length; i++) {
//Learn regex test function!
if (regex.test(tr1[i].id)) //if a match found
//display children
document.getElementById(tr1[i].id).style.visibility = "visible";
}
}

Related

Question on Traversing an HTML table with JavaScript and DOM Interfaces

I followed the example here: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Traversing_an_HTML_table_with_JavaScript_and_DOM_Interfaces
But I have 2 things I can't figure out.
The first is how do I add a class name for all the td elements?
The second, is how do I inject this table into a div named "main",
rather than document.getElementsByTagName("body")[0];
I don't really understand the [0] at the end of the document.getElementsByTagName("body"), why is it necessary?
The first is how do I add a class name for all the td elements?The
first is how do I add a class name for all the td elements?
classList.add
The second, is how do I inject this table into a div named "main"
getElementById
I don't really understand the [0] at the end of the
document.getElementsByTagName("body")
Because getElementsByTagName is generic. It can return multiples for any tag. [0] says "give me the first", and since it's BODY, we pretty much are sure there's only one.
function start() {
// get the reference for the body
var mybody = document.getElementById("main");
// creates <table> and <tbody> elements
mytable = document.createElement("table");
mytablebody = document.createElement("tbody");
// creating all cells
for(var j = 0; j < 3; j++) {
// creates a <tr> element
mycurrent_row = document.createElement("tr");
for(var i = 0; i < 4; i++) {
// creates a <td> element
mycurrent_cell = document.createElement("td");
mycurrent_cell.classList.add("myClass");
// creates a Text Node
currenttext = document.createTextNode("cell is row " + j + ", column " + i);
// appends the Text Node we created into the cell <td>
mycurrent_cell.appendChild(currenttext);
// appends the cell <td> into the row <tr>
mycurrent_row.appendChild(mycurrent_cell);
}
// appends the row <tr> into <tbody>
mytablebody.appendChild(mycurrent_row);
}
// appends <tbody> into <table>
mytable.appendChild(mytablebody);
// appends <table> into <body>
mybody.appendChild(mytable);
// sets the border attribute of mytable to 2;
mytable.setAttribute("border","2");
}
start();
.myClass {
color:red;
}
<div id="main"></div>

JS create new child TR with two TD bits of information

I have the following problem - I am having difficulty creating the new TR row dynamically and then getting it to insert the data as a new table (TD) line.
The full question is as below;
Create a script that inserts a new row with the values March and £580 as the last child of the following HTML table.
<table id=”takings”>
<tr>
<td>January</td>
<td>£100</td>
</tr>
<tr>
<td>February</td>
<td>£300</td>
</tr>
// insert here
</table>
My attempt or idea was to create the TR first and then for each item in the text array add a TD within that newly created TR. However this doesn't seem to create anything.
My JS is as below;
function insertNode(newNodeTypeTD, newNodeTypeTR, newNodeTextArray, element) {
let parentElement = document.getElementById(element);
let newTR = document.createElement(newNodeTypeTR);
for (let i = 0; newNodeTextArray.length; i++) {
let newText = document.createTextNode(newNodeTextArray);
newTR.appendChild(newText);
parentElement.insertBefore(newTR, parentElement.children[i]);
}
}
window.onload = function() {
insertNode("td", "tr", ["March", "£580"], "takings")
}
Note this line: for (let i = 0; newNodeTextArray.length; i++) {
newNodeTextArray.length is 1 or greater, so this condition always returns true.
What you likely meant to do was
for (let i = 0; i < newNodeTextArray.length; i++) {

Click on two Table cells highlight their content and store their values in variables

I am getting a Table from a database like this (row numbers may vary):
|Player 1|Player 2|
-------------------
|Danny |Danny |
|John |John |
|Mary |Mary |
I want to select two names, one from each Player column, and store them in two variables, say player1_id and player2_id which I will later use to insert data into the database. I also want to highlight the names when they are clicked. The highlight and the associated variable value should change when I click on another name.
For example, let's say I click on Danny and John from Player 1 and Player 2 respectively. These two names should get highlighted and the variables should get player1_id = "Danny" and player2_id = "John". If I change my mind and click on Mary on the Player 2 column, Mary should get highlighted, John should lose its highlight and player2_id should change to "Mary"
So far I managed to sort of getting only the highlight part (but when I click more than one names all stay highlighted). Could anyone point me to a correct direction, please?
Here is the JSFiddle code of what I have so far
try this: https://jsfiddle.net/dunsondog109/behcgwLf/7/
function inputClickHandler(e){
e = e||window.event;
var all = document.getElementsByTagName("td");
var tdElm = e.target||e.srcElement;
var tdIndex = tdElm.cellIndex;
var numberOfColumns = 2;
if(tdElm.style.backgroundColor == 'rgb(46, 204, 64)'){
tdElm.style.backgroundColor = '';
} else {
for (var i=0;i<all.length;i++) {
if (i%numberOfColumns==tdIndex%numberOfColumns) {
// It is in the same column
all[i].style.backgroundColor = '';
}
}
tdElm.style.backgroundColor = '#2ECC40';
}
}
You need to reset all the tds in your column first and then set the td that was clicked
maybe it will not help you, but this is what I created for fun ...
As I'm jQuery user I find it difficult to list the table for any actions using plain javascript ... I would prefer having list of players in some object, draw the table based on that list. Instead of adding css to table cell i would add class like active and then just easily remove / move that class to different player. Maybe even adding some classes or other data-attributes to the table cells to help identify correct row / cell ... Anyway, everything is possible, but with this design you will not get far with your project I think. Good luck.
var Game = function() {
var players = {};
var table = document.querySelector('#myTable');
var rows = table.querySelectorAll('tr');
function uncheckPlayers(col) {
for ( var i=0; i<rows.length; i++ ) {
var tds = rows[i].querySelectorAll('td');
for ( var x=0; x<tds.length; x++ ) {
if ( col === x ) {
tds[x].style.backgroundColor = '';
}
}
}
}
for ( var i=0; i<rows.length; i++ ) {
var tds = rows[i].querySelectorAll('td');
for ( var x=0; x<tds.length; x++ ) {
tds[x].addEventListener('click', function() {
var id = x;
return function() {
uncheckPlayers(id);
players[id] = new Player(id, this.innerText);
this.style.backgroundColor = 'red';
console.log(players);
}
}(x));
}
}
}
var Player = function(id, name) {
this.name = name;
this.id = id;
this.score = 0;
console.log(this);
};
var Game = new Game();
<html>
<head>
<title>Find table cell value on cell (table) click using JavaScript</title>
</head>
<body>
<center>
Click on table below to select Players.
<br />
<br />
</center>
<table align="center" id="myTable" border="1" style="cursor: pointer;">
<tr>
<th>Player 1</th><th>Player 2</th>
</tr>
<tr>
<td>Danny</td><td>John</td>
</tr>
<tr>
<td>John</td><td>Danny</td>
</tr>
<tr>
<td>Mary</td><td>Mary</td>
</tr>
</table>
<br />
</body>
</html>

Repeat script for multiple elements

Hey i have this code:
<body>
<table>
<tr>
<td class="first">100</td>
</tr>
</table>
<h4 class=curs style="display:none">10</h4>
<script>
document.body.onload = function(){
var firstTdVal = document.getElementsByClassName('first')[0].innerHTML;
var secondTdVal = document.getElementsByClassName('curs')[0].innerHTML;
var valueToBeShown = parseInt(firstTdVal)/ parseInt(secondTdVal);
document.getElementsByClassName('first')[0].innerHTML = valueToBeShown ;
}
</script>
</body>
As you see ".first" has a number in it,this number is divied to ".curs" and the result is showed in ".first" too.Now the problem is that for exemple i add 100 more td's with class ".second,.third...,.hundred" in table.How to make script to do the same for all td's as it does for the ".first"(devide to ".curs").How do i do this in my JS by keeping it complex.
Use document.querySelectorAll to get an array of matched elements (matched with CSS selector), then loop through them using forEach, applying you logic one td at a time. Like this:
// querySelector gets the first element matched. textContent get the text of that element
var cursValue = parseInt(document.querySelector(".curs").textContent);
// querySelectorAll get an array of all the matched elements
var tds = document.querySelectorAll("td");
// loop through that array one td at a time
tds.forEach(function(td){
// get the text of the current td
var value = parseInt(td.textContent);
// if the value is not valid (a string for example) return and don't process anymore for this td (go straight to the next one).
if(isNaN(value)) return;
// calculate the new value
value = value / cursValue;
// change the text of this td (update it to the new value)
td.textContent = value;
});
NOTE: querySelector and querySelectorAll match elements using CSS selectors, so to match an element using a class the selector should be ".className", to match it using an ID: "#someID", ... All CSS selectors are accepted (even this one: "#anID>li.some-class a:not([href])").
NOTE2: tds is an array, so if you don't want to use forEach you can use a normal for loop (for(var i = 0; i < tds.length; i++) ...).
This will iterate over your table (be sure to set the table ID) (open dev console to view output but it's pretty straight forward.)
var table = document.getElementById("myTable");
for (var row of table.rows) {
for (var col of row.cells) {
console.log(col.className, col.innerHTML); //Class names and the values of the elements.
}
}
If you need anymore help please ask because I do not fully understand what you're trying to do here.
Here's a way where you put the number to be divided by in the first td, the number to divide by in the second td, and the result will be placed in the third td.
var trs = document.getElementsByTagName('tr');
for (var i = 0; i< trs.length; i++) {
var tds = trs[i].getElementsByTagName('td'),
first = tds[0].textContent,
second = tds[1].textContent,
third = tds[2],
result = (parseInt(first) / parseInt(second));
third.innerHTML = result;
}
<table>
<tr>
<td>10</td>
<td>2</td>
<td></td>
</tr>
<tr>
<td>4</td>
<td>2</td>
<td></td>
</tr>
</table>

Not able to push data into array

I am trying to get to the logic of the Tic Tac Toe game which I almost have made a logic, but I am stuck while pushing the Data to the array. Here is a fiddle that I have created.
http://jsfiddle.net/afzaal_ahmad_zeeshan/6bgjp/1/
Let me explain the whole thing to you!
I am trying to use the 9 td of the table as the 8 rows of the possible win. For that I have given some of the tds a className depending on their location in the table.
The HTML is simple
<div class="vicvacvoe">
<table>
<tr>
<td class="line1 line4 line7"></td>
<td class="line1 line5"></td>
<td class="line1 line6 line8"></td>
</tr>
<tr>
<td class="line2 line4"></td>
<td class="line2 line5 line7 line8"></td>
<td class="line2 line6"></td>
</tr>
<tr>
<td class="line3 line4 line8"></td>
<td class="line3 line5"></td>
<td class="line3 line6 line7"></td>
</tr>
</table>
</div>
Just a simple table with 9 tds, the CSS is not relative to this so leave it I guess.
jQuery for this also simple one. But I am not able to push the data to the Array.
var vic = $('.vicvacvoe table tr td');
var player = 1;
var tick = '✓';
var cross = 'X';
var user1 = [];
var user2 = [];
vic.click(function () {
var className = $(this).attr('class');
if (className != 'dead') {
// A new board place to write on...
// Now do the processes here...
if (player == 1) {
// First player!
var cArray = className.split(' ');
for (i = 0; i < cArray.length; i++) {
for (j = 0; j < user1.length; j++) {
// check for each class
if (user1[j] != cArray[i]) {
user1.push(cArray[i]);
}
}
}
} else {
/* code for second player, the same */
}
$(this).text('Works!');
$(this).attr('class', 'dead');
}
});
This is the entire jQuery script. Actually when I run the code, it really does go to the end of the stack (to the class attribute change script) and it locks the td for further process and it write Works! in the td too. But I am not able to get the classNames inside the Array for that user. I want to save the line number for each user and then check whether he has 3 spots filled or not. I need help with the Array part.
Thanks!
I prefer simplicity so you could use indexOf to check whether the class is already in the users' array like so:
if (player == 1) {
// First player!
var cArray = className.split(' ');
for (i = 0; i < cArray.length; i++) {
if(user1.indexOf(cArray[i]) == -1) {
user1.push(cArray[i]);
} else {
// css class is already in the array
}
}
}
Your issue is here:
for (j = 0; j < user1.length; j++) {
The only place you add to the user1 array is within this loop. Now the array is initially empty, so clearly this loop will never iterate as user1.length is always 0.
I think your intent with this bit of code was to check if the value was already in the array in which case I suggest using $.inArray.

Categories

Resources