This is the board drawing function
this.drawBoard=function(){
document.write('<table id="newGame">');
for(let i=0;i<boxes;i++){
document.write('<tr>');
for(let j=0;j<boxes;j++){
document.write(' <td id=" '+ i +' , '+ j + ' " ');
document.write('</td>');
}
document.write('</tr>');
}
document.write('</table>');
b.onClickEvent();
}
While this is the function to get the id
i found that by changing the 0 index in line clicked = cell.getElementsByTagName("td")[0].id; I can get to the column I want but don't know how to manipulate it to get the exact cell id
this.onClickEvent=function() {
let table = document.getElementById("newGame");
let rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
let currentRow = table.rows[i];
var createClickHandler =
function(cell) {
return function() {
clicked = cell.getElementsByTagName("td")[0].id;
console.log(clicked);
let numbers=[];
clicked.replace(/(\d[\d\.]*)/g, function( x ) { var n = Number(x); if (x == n) { numbers.push(x); } })
b.spliceGrid(numbers[0],numbers[1]);
numbers=[];
};
};
currentRow.onclick = createClickHandler(currentRow);
}
}
tables elements have properties like rowIndex or cellIndex, you don't need to use id for each cell.
Then, you even have access to any cell you want to get or set anything on it, like change it's background ( to pink ):
myTable.rows[2].cells[1].classList.add('BgPink');
this way:
const myTable = newTable(4,5);
myTable.rows[2].cells[1].classList.add('BgPink');
function newTable( rowCount, cellCount )
{
const TableX = document.body.appendChild(document.createElement('table'))
;
for( let r=0; r < rowCount; ++r )
{
let newRow = TableX.insertRow();
for( let c=0; c < cellCount; ++c )
{
newRow.insertCell().textContent = `${r},${c}`;
}
}
return TableX;
}
myTable.onclick = e => // event delegation method
{
if (!e.target.matches('td')) // to accept only clicks over a <TD> element
return;
let
index_Cell = e.target.cellIndex
, index_Row = e.target.closest('tr').rowIndex
;
console.clear();
console.log('clicked on :', index_Row, index_Cell );
}
table {
border-collapse : collapse;
}
table td {
padding : .2em .8em;
border : 1px solid darkblue;
text-align : center;
cursor : pointer;
}
.BgPink {
background : pink;
}
Related
I am attempting to create a grid that contains one letter in each box (like a Word Find puzzle).
I have successfully created a grid that shows w/ the determined number of cols/rows, but when I attempt to put one letter in each box, I get the following ten times in each box instead of a single letter:
[object
Object]
Here is the JavaScript:
$(function() {
var letters = [
'rzeabppssgcddrvddydtjrkei', // 1
'cezcqubhniittonieqerbiuvm', // 2
'jqcjnasionsncvbsrwtabddsu', // 3
'olselesitneagittrjanreinv', // 4
'nqnaisdenmeibvurellsnrioc', // 5
'ydnlevrnyeaidrwifkufmsuis', // 6
'dcccjeeaogsemudbeemefaptn', // 7
'evonsqpdepislsnudnurwjbpo', // 8
'grytiunnafsexattmtclaimoi', // 9
'pnqrhocbiieeinoitacilppat', // 10
];
var letter = [];
function splitRows(arr, arr2) {
for (let i=0; i < arr.length; i++) {
arr[i].split();
for (let j=0; j < arr.length; j++) {
arr2[j] = arr[i][j];
}
}
}
splitRows(letters, letter);
function* gen(arr) {
for(i=0; i < arr.length; i++) {
yield arr[i];
}
}
function generateGrid(rows, cols, arr) {
var grid = "<table>";
for(row = 1; row <= rows; row++) {
grid += "<tr>";
for(col = 1; col <= cols; col++) {
grid += "<td>";
for(let i=0; i < arr.length; i++) {
grid += gen(arr).next(); // not sure if the .next() generator works yet
}
grid += "</td>"; // 'letters' needs to input the next letter in letters each time it is called
}
grid += "</tr>";
}
return grid;
}
$("#tableContainer").append(generateGrid(26, 22, letter));
});
The first function is intended to take rows and split them into singular letters (eventually taking rows as an input, but for testing purposes I have them in an array)
The second function is a generator to insert into the generateGrid() function that is used to generate the next letter in the sequence each time a box is created.
You should convert your string data to a matrix first then you can run the matrix through a table.
The following jQuery plugin clears the table and replaces it with rows and columns based on the data.
Note: I also added in tag name validation, in the case where the element the plugin was being invoked upon was not a <table> element.
var DEBUG_EXPERIMENTAL = false;
initializePlugins(); // Forward Declaration of jQuery plugins
let rawStringData = `
rzeabppssgcddrvddydtjrkei
cezcqubhniittonieqerbiuvm
jqcjnasionsncvbsrwtabddsu
olselesitneagittrjanreinv
nqnaisdenmeibvurellsnrioc
ydnlevrnyeaidrwifkufmsuis
dcccjeeaogsemudbeemefaptn
evonsqpdepislsnudnurwjbpo
grytiunnafsexattmtclaimoi
pnqrhocbiieeinoitacilppat
`;
$('.word-search').buildWordSearch(rawStringData, 'letter');
$('.letter').enableHighliting('highlight');
function initializePlugins() {
(($) => {
$.stringToMatrix = function(str) {
return str.trim().split('\n').map(row => row.trim().split(''));
};
$.fn.buildWordSearch = function(stringData, cellClass) {
this.throwErrorIfNotType('TABLE');
return this.append($('<tbody>')
.append($.stringToMatrix(stringData).map(row => {
return $('<tr>').append(row.map(col => {
return $('<td>').addClass(cellClass).text(col);
}));
})));
};
$.fn.throwErrorIfNotType = function(expectedTagName) {
let actualTagName = this.prop('tagName');
if (actualTagName !== expectedTagName) {
throw Error(`Element '${actualTagName}' is not a '${expectedTagName}'!`);
}
};
$.fn.getCell = function(x, y) {
return this.find(`tr:nth-child(${y + 1}) td:nth-child(${x + 1})`);
};
$.fn.enableHighliting = function(cls) {
return this.each(() => {
this.on({
mouseover: function() {
let $table = $(this).closest('table');
let $row = $(this).closest('tr');
let rowIndex = $row.index();
let colIndex = $(this).index();
let rowCount = $table.find('tbody tr').length;
let colCount = $row.find('td').length;
// Hightlights diagonals.
if (DEBUG_EXPERIMENTAL) {
let limit = rowCount;
let xNeg = colIndex - 1;
let xPos = colIndex + 1;
let yNeg = rowIndex - 1;
let yPos = rowIndex + 1;
while (limit > 0) {
if (xNeg > -1 && yNeg > -1) {
$table.getCell(xNeg, yNeg).addClass(cls);
}
if (xPos < colCount && yNeg > -1) {
$table.getCell(xPos, yNeg).addClass(cls);
}
if (xNeg > -1 && yPos < rowCount) {
$table.getCell(xNeg, yPos).addClass(cls);
}
if (xPos < colCount && yPos < rowCount) {
$table.getCell(xPos, yPos).addClass(cls);
}
xNeg--;
xPos++;
yNeg--;
yPos++;
limit--;
}
}
$row.addClass(cls);
$table.find(`td:nth-child(${colIndex + 1})`).addClass(cls);
},
mouseout: function() {
let $table = $(this).closest('table');
let $row = $(this).closest('tr');
let rowIndex = $row.index();
let colIndex = $(this).index();
let rowCount = $table.find('tbody tr').length;
let colCount = $row.find('td').length;
// Un-hightlights diagonals.
if (DEBUG_EXPERIMENTAL) {
let limit = rowCount;
let xNeg = colIndex - 1;
let xPos = colIndex + 1;
let yNeg = rowIndex - 1;
let yPos = rowIndex + 1;
while (limit > 0) {
if (xNeg > -1 && yNeg > -1) {
$table.getCell(xNeg, yNeg).removeClass(cls);
}
if (xPos < colCount && yNeg > -1) {
$table.getCell(xPos, yNeg).removeClass(cls);
}
if (xNeg > -1 && yPos < rowCount) {
$table.getCell(xNeg, yPos).removeClass(cls);
}
if (xPos < colCount && yPos < rowCount) {
$table.getCell(xPos, yPos).removeClass(cls);
}
xNeg--;
xPos++;
yNeg--;
yPos++;
limit--;
}
}
$row.removeClass(cls);
$table.find(`td:nth-child(${colIndex + 1})`).removeClass(cls);
}
});
});
};
})(jQuery);
}
.word-search {
border: 2px solid #000;
border-collapse: collapse;
}
.word-search td {
width: 1.25em;
height: 1.25em;
line-height: 1.25em;
text-align: center;
}
.highlight {
background: #FFD;
}
.letter.highlight:hover {
background: #FF0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="word-search"></table>
In table like the one below in the code snippet I would like that once clicked an item, I want to change the name of the selected cell to the next name corresponding to the sequence like in the array. [square, triangle, circle, oval, pentagon] So if I click "square", now the name appearing on it should be "triangle".
var card = [
{name:'square'},
{name:'triangle'},
{name:'circle'},
{name:'oval'},
{name:'pentagon'}
];
function generateTable(grid, rows, cols) {
var row;
var cells = rows * cols;
for(var i=0; i < cells; i++){
// track row length and insert new ones when necessary
// also creates the first row
if(i % cols == 0) {
row = grid.insertRow(-1);
}
// track our position in the card list
// modulo operator lets us loop through the cards repeatedly
var thisCard = card[i % card.length];
cell = row.insertCell(-1);
cell.innerHTML = thisCard.name;
cell.style.backgroundColor = '#D3D3D3';
}
}
generateTable(document.getElementById('grid'), 7, 7);
<table id="grid">
</table>
"I want the value to change to the next in the sequence" (clarification from a comment that it isn't the element to the right that matters, it's the sequence in the array)
OK, so I would probably use a (delegated) click handler attached to the table element. Get the value of the clicked td element and look it up in the card array, then from there get the next item from the array. Maybe a little something like this:
document.getElementById('grid').addEventListener("click", function(e) {
if (e.target.nodeName.toLowerCase() === "td") {
var currentIndex = card.findIndex(function(shape) {
return shape.name === e.target.innerHTML;
});
e.target.innerHTML = card[(currentIndex + 1) % card.length].name;
}
});
var card = [
{name:'square'},
{name:'triangle'},
{name:'circle'},
{name:'oval'},
{name:'pentagon'}
];
function generateTable(grid, rows, cols) {
var row;
var cells = rows * cols;
for(var i=0; i < cells; i++){
// track row length and insert new ones when necessary
// also creates the first row
if(i % cols == 0) {
row = grid.insertRow(-1);
}
// track our position in the card list
// modulo operator lets us loop through the cards repeatedly
var thisCard = card[i % card.length];
cell = row.insertCell(-1);
cell.innerHTML = thisCard.name;
cell.style.backgroundColor = '#D3D3D3';
}
}
generateTable(document.getElementById('grid'), 7, 7);
<table id="grid">
</table>
I have used the array .findIndex() method to find the item in the array, so if you want to support IE you'll need a polyfill, or of course you could just use a for loop or whatever.
You can access cells by their cellIndex property. So once you have the cell that was clicked on, get the cell to the right (if it exists) and update the innerHTML of the clicked on cell.
function changeName(e){
// Get the element that was clicked on
var cell = e.target;
var row, index;
// If it's a td, update the innerHTML
if (cell && cell.tagName.toLowerCase() == 'td') {
// Get the row that the cell is in
row = cell.parentNode;
// Get index of cell to right
index = cell.cellIndex + 1;
// Make sure cell to right exists
if (row.cells[index]) {
// Update clicked on cell
cell.innerHTML = row.cells[index].innerHTML;
}
}
}
window.onload = function(){
document.querySelector('table').addEventListener('click',changeName);
}
td {
width: 5em;
border: 1px solid #999999;
}
<table>
<tr><td>square<td>triangle<td>circle<td>oval<td>pentagon
</table>
Here is a more concise version:
window.onload = function() {
document.querySelector('table').addEventListener('click',
function(e) {
var cell = e.target;
var next = cell.cellIndex === undefined? null : cell.parentNode.cells[cell.cellIndex + 1];
if (next)
cell.innerHTML = next.innerHTML
});
};
td {
width: 5em;
border: 1px solid #999999;
}
<table>
<tr><td>square<td>triangle<td>circle<td>oval<td>pentagon
</table>
Edit
Updated to loop through the names in succession
var card = [
{name:'square'},
{name:'triangle'},
{name:'circle'},
{name:'oval'},
{name:'pentagon'}
];
function getNextCard(name) {
}
window.onload = function() {
document.querySelector('table').addEventListener('click',
function(e) {
var node = e.target;
var name = node.textContent;
var index;
if (node.tagName.toLowerCase() == 'td') {
index = (card.findIndex(function(obj){
return obj.name == name;
}) + 1) % card.length;
node.textContent = card[index].name;
}
});
};
td {
width: 5em;
border: 1px solid #999999;
}
<table>
<tr><td>square<td>triangle<td>circle<td>oval<td>pentagon
</table>
Please feel free to optimize this solution. Hope this works for you and this is what you want :)
var card = [{
name: 'square'
},
{
name: 'triangle'
},
{
name: 'circle'
},
{
name: 'oval'
},
{
name: 'pentagon'
}
];
function onCellClick(td) {
value = td.innerHTML.trim();
for (var i = 0; i < card.length; i++) {
var index;
if (card[i].name === value) {
index = i + 1;
if (card.length - 1 === i) {
index = 0
}
td.innerHTML = card[index].name;
break;
}
}
}
function generateTable(grid, rows, cols) {
var row;
var cells = rows * cols;
for (var i = 0; i < cells; i++) {
// track row length and insert new ones when necessary
// also creates the first row
if (i % cols == 0) {
row = grid.insertRow(-1);
}
// track our position in the card list
// modulo operator lets us loop through the cards repeatedly
var thisCard = card[i % card.length];
cell = row.insertCell(-1);
cell.innerHTML = thisCard.name;
cell.onclick = function() {
onCellClick(this);
};
cell.style.backgroundColor = '#D3D3D3';
}
}
generateTable(document.getElementById('grid'), 7, 7);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="grid">
</table>
I am trying to create a minefield game with javascript.
When I click on clear ro**w it gives "passed" but sometimes "died" too or clicking on **mined row gives sometimes "passed". It's supposed to give only "passed" with clear and "died" with mined row.
I can't figure out the reason..
Could you see it?
Here is my code so far:
var level = 9;
// create the table
var body = document.getElementsByTagName("body")[0];
var tbl = document.createElement("table");
tbl.setAttribute('id', 'myTable');
var tblBody = document.createElement("tbody");
//Create 2d table with mined/clear
for (var i = 1; i <= 10; i++) {
var row = document.createElement("tr");
document.write("<br/>");
for (var x = 1; x <= 10; x++) {
var j = Math.floor(Math.random() * 50);
if (j <= 15) {
j = "mined";
} else {
j = "clear";
}
var cell = document.createElement("td");
var cellText = document.createTextNode(j + "");
cell.appendChild(cellText);
row.appendChild(cell);
}
tblBody.appendChild(row);
}
tbl.appendChild(tblBody);
body.appendChild(tbl);
tbl.setAttribute("border", "1");
//Check which row is clicked
window.onload = addRowHandlers;
function addRowHandlers() {
var table = document.getElementById("myTable");
var rows = table.getElementsByTagName("td");
for (p = 0; p < rows.length; p++) {
var currentRow = table.rows[p];
var createClickHandler = function (row) {
return function () {
var cell = row.getElementsByTagName("td")[1];
var id = cell.innerHTML;
if (id == "mined") {
alert("Died");
} else {
alert("Passed!");
}
};
}
currentRow.onclick = createClickHandler(currentRow);
}
}
JSFiddle Here:
http://jsfiddle.net/blowsie/ykuyE/
Thanks in advance!
Its' this line, which causes the faulty behaviour: var cell = row.getElementsByTagName("td")[1]; Everytime a click is made, the [1] selects the 2nd cell of a column, no matter which cell was actually clicked.
I modified your fiddle: http://jsfiddle.net/ykuyE/1
The onclick handler is now applied to the individual cell directly, when the table is created.
cell.onclick = function() {
if (this.innerHTML == "mined") {
alert("Died");
} else {
alert("Passed!");
}
}
I have this table and I want to find a hidden control's value inside the tr .
I tried this javascript
function DeleteGridview_Row(pid) {
alert(pid);
var table = document.getElementById('<%= gvResults_gov.ClientID %>');
rows = table.getElementsByTagName('tr');
var i;
var j;
var cells;
var customerId;
for (i = 0, j = rows.length; i < j; ++i) {
cells = rows[i].getElementsByTagName('td');
if (!cells.length) {
continue; }
customerId = cells[0].innerHTML;
}
alert(customerId);
}
HTML
<table cellpadding="4" style="color: #333333; border-width: 0px; border-style: Groove;
width: 100%; font-weight: bold; width: 100%;" id="MainContent_gvResults_gov"
class="box-table-b">
<tbody>
<tr >
<td>
<input type="hidden" value="6532" id="MainContent_gvResults_gov_hdDocID_0" name="ctl00$MainContent$gvResults_gov$ctl02$hdTocID">
</td>
<td>
1010041215
</td>
</tr>
</tbody>
</table>
remove the enter code here
if the code is complete you need an ending }
If the customer ID is 1010041215 you need the second cell (from 0)
for (i = 0, j = rows.length; i < j; ++i) {
cells = rows[i].getElementsByTagName('td');
if (!cells.length) {
continue; }
customerId = cells[1].innerHTML; // [1] is the second cell
}
}
change
customerId = cells[1].innerHTML; // [1] is the second cell
to
customerId = cells[1].getElementsByTagName("input")[0].value
if you want the value of the input field
However tables have rows and cells:
function DeleteGridview_Row(pid) {
var customerId = "";
var table = document.getElementById('<%= gvResults_gov.ClientID %>');
var rows = table.rows;
for (i = 0, n = rows.length; i < n; ++i) {
cells = rows[i].cells;
if (!cells.length) {
continue; }
customerId = cells[1].innerHTML;
}
}
return customerId;
}
How can I toggle multiple rows in a table if the <td> class is set to an specific class. For instance toggle all rows if they contain the class="foo".
<table id="bar">
<tr>
<td>hello</td>
<td class="foo">there</td>
<td class="foo">bye</td>
</tr>
</table>
Here's a non-jQuery solution, written just for you: http://phrogz.net/tmp/toggling_rows_with_class.html
Here's the relevant JS:
window.onload = function() {
var visible = true;
document.getElementById('toggle').onclick = function() {
visible = !visible;
var tds = findElementsWithClass('td', 'foo');
for (var i=0, len=tds.length; i<len; ++i) {
tds[i].parentNode.style.display = visible ? '' : 'none';
}
};
}
function findElementsWithClass(tagName, className) {
if (document.querySelectorAll) {
return document.querySelectorAll(tagName + "." + className);
} else {
var results = [];
var all = document.getElementsByTagName(tagName);
var regex = new Regexp("(?:^|\\s)" + tagName + "(?:\\s|$)");
for (var i=0, len=all.length; i<len; ++i) {
if (regex.test(all[i].className)) {
results.push(all[i]);
}
}
return results;
}
}
Modify the class
Why is everyone using selectors? There is already a class attached to all the appropriate elements, so why not just modify the class?
This function will find the class of a given name, and set an attribute for that class. Be careful if you have multiple classes with coincident names in different stylesheets, because the function isn't!
function changeStyle(stylename,attribute,newvalue) {
var cssRules = 'rules';
if(document.styleSheets[0].cssRules) {
cssRules = 'cssRules';
}
for(var sheetId=0; sheetId<document.styleSheets.length; sheetId++) {
var sheet = document.styleSheets[sheetId];
for(var ruleId=0; ruleId<sheet[cssRules].length; ruleId++) {
var rule = sheet[cssRules][ruleId];
if(rule.selectorText == "."+stylename) {
rule.style.setProperty(attribute,newvalue,"");
}
}
}
return false;
}
Now, just call
changeStyle('foo','display','none');
and the cells should disappear, then with 'block' to get them back (IE can't do the more recent display styles like ). I suspect that in a table you'll want to hide entire rows rather than just cells, but you can also make them disappear by setting visibility to hidden - they will still take up space, but not draw.
See, no jquery, no homemade element selectors. Just a slightly annoying bit of javascript to loop through the stylesheets and their rules...
td = document.getElementsByTagName('td');
for (var i = 0; i < td.length; i++) {
if (td[i].className === 'foo')
if (!td[i].style.display)
td[i].style.display = 'none';
else
td[i].style.display = '';
}
}
http://jsfiddle.net/qwertymk/cyZn9/2/
Something like this should do it:
var trs = document.getElementsByTagName("tr");
for (var i in trs) {
var tr = trs[i];
if (tr.getElementsByClassName("foo").length > 0)
tr.style.display = (tr.style.display == "none" ? "block" : "none");
}
This will toggle the display on any TR that contains a child with class="foo".
Something like this?
$("table td.specific_class").toggle();
Edit
/* Go through the table rows */
var trs = document.getElementsByTagName("tr");
for (var i = 0; i < trs.length; i++ ) {
var myClass, tds, line_done = false;
/* Go through the table cells */
tds = trs[i].getElementsByTagName("td");
for ( var k = 0; k < tds.length; k++ ){
/* Check each class of each cell */
myClasses = tds[k].className.split(' ');
for ( var j = 0; j < myClasses.length; j++ ){
/* If the class corresponds we toggle the row and break until the next row */
if ( myClasses[j].className == "foo" ){
trs[i].style.display = trs[i].style.display == "none" ? "block" : "none";
line_done = 1;
break;
}
}
if ( line_done ){
break;
}
}
}
try this one
<html>
<head>
<title>test</title>
<script type="text/javascript">
var toggle = function (action) {
var trs = document.getElementById('bar').getElementsByTagName('tr'),
trs_count = trs.length,
needed = [],
total = 0,
pattern = /\bfoo\b/g,
initial= 'show';
for (i=0; i<trs_count; i++) {
var tds = trs[i].getElementsByTagName('td'),
tds_count = tds.length;
for (j=0; j<tds_count; j++) {
if (pattern.exec(tds[j].className)) {
needed.push(tds[j]);
total++;
}
}
}
toggle = function (action) {
if (this.display == null) {
this.display = initial;
}
if (action == null) {
this.display = (this.display == 'hide') ? 'show' : 'hide';
}
else {
this.display = action;
}
for (i=0; i<total; i++) {
if (this.display == 'show') {
needed[i].style.display = 'block';
}
else {
needed[i].style.display = 'none';
}
}
return true;
}
return toggle();
}
</script>
</head>
<body>
<table id="bar">
<tr><th>Header</th></tr>
<tr><td class="foo">1 Data foo</td></tr>
<tr><td>2 Data</td></tr>
<tr><td class="foo">3 Data foo</td></tr>
<tr><td>4 Data</td></tr>
</table>
<button type="button" onclick="toggle()">toggle</button>
</body>
</html>