Tic Tac Toe - Check win (Vanilla JS) - javascript

I did a nested array that simulates the situation in the table, and it seems to work fine.
My goal was to run on this array every move to check if there is a win.
It divided into 3 parts: column checker, row checker, and slant checker, but for some reason, I don't see the alert "win".
Thanks very much!
relevant code:
Html
<main>
<table class="delete">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</main>
CSS
.cross {
background-image: url(x.png);
background-size: cover;
}
.circle {
background-image: url(circle.png);
background-size: cover;
}
table {
border-collapse: collapse;
width: 50vw;
height: 70vh;
border: 5px solid black;
margin: auto;
}
td {
border: 5px solid black;
}
Vanilla JS
let table = document.getElementsByTagName("table")[0];
let saveTypeGame;
let friendTurn = 0;
let arr = [[],[],[]];
let colWin = 0;
if(saveTypeGame=="friend")
{
table.addEventListener("click", function (e1) {
if (friendTurn%2 == 0)
{
e1.target.classList.add("cross");
arr[parseInt(e1.target.cellIndex)][parseInt(e1.target.parentElement.rowIndex)] = "cross";
}
else {
e1.target.classList.add("circle");
arr[parseInt(e1.target.cellIndex)][parseInt(e1.target.parentElement.rowIndex)] = "circle";
}
//columns winning
for(let z = 0; z<2; z++)
{
//columns winning
if(arr[z][0] == arr[z][1] == arr[z][2])
{
alert("win");
}
//rows winning
if(arr[0][z] == arr[1][z] == arr[2][z])
{
alert("win");
}
//slant winning
if(arr[0][0] == arr[1][1] == arr[2][2])
{
alert("win");
}
}
friendTurn++;
})
}
.cross {
background-image: url(x.png);
background-size: cover;
background: red;
}
.circle {
background-image: url(circle.png);
background-size: cover;
background: green;
}
table {
border-collapse: collapse;
width: 50vw;
height: 70vh;
border: 5px solid black;
margin: auto;
}
td {
border: 5px solid black;
}
<html>
<head>
</head>
<body>
<main>
<table class="delete">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</main>
<script>
(function() {
// your page initialization code here
// the DOM will be available here
let table = document.getElementsByTagName("table")[0];
let saveTypeGame;
let friendTurn = 0;
let arr = [[],[],[]];
let colWin = 0;
if(true)//saveTypeGame=="friend")
{
table.addEventListener("click", function (e1) {
if (friendTurn%2 == 0)
{
e1.target.classList.add("cross");
arr[parseInt(e1.target.cellIndex)][parseInt(e1.target.parentElement.rowIndex)] = "cross";
}
else {
e1.target.classList.add("circle");
arr[parseInt(e1.target.cellIndex)][parseInt(e1.target.parentElement.rowIndex)] = "circle";
}
//columns winning
for(let z = 0; z<2; z++)
{
//columns winning
if(arr[z][0] == arr[z][1] == arr[z][2])
{
alert("win");
}
//rows winning
if(arr[0][z] == arr[1][z] == arr[2][z])
{
alert("win");
}
//slant winning
if(arr[0][0] == arr[1][1] == arr[2][2])
{
alert("win");
}
}
friendTurn++;
})
}
})()
</script>
</body>
</html>

You can't compare items in sequence like you did.
if(arr[0][0] == arr[1][1] == arr[2][2]) // don't work
Instead you need to chain the comparisons:
if ( arr[0][0] == s &&
arr[1][1] == s &&
arr[2][2] == s)
let table = document.getElementsByTagName("table")[0];
let friendTurn = 0;
let arr = [
[],
[],
[]
];
table.addEventListener("click", function(e1) {
let cellIndex = parseInt(e1.target.cellIndex);
// check if cell isn't clicked
if (!e1.target.classList.contains("cross") &&
!e1.target.classList.contains("circle") &&
// check for border clicks
arr[cellIndex] !== undefined) {
let s = "circle";
if (friendTurn % 2 == 0) s = "cross";
friendTurn++;
let rowIndex = parseInt(e1.target.parentElement.rowIndex);
arr[cellIndex][rowIndex] = s;
e1.target.classList.add(s);
for (let z = 0; z <= 2; z++) {
if (arr[z][0] == s &&
arr[z][1] == s &&
arr[z][2] == s) {
reset("columns" + z, s);
}
if (arr[0][z] == s &&
arr[1][z] == s &&
arr[2][z] == s) {
reset("rows" + z, s);
}
}
if (arr[0][0] == s &&
arr[1][1] == s &&
arr[2][2] == s) {
reset("slant1", s);
}
if (arr[0][2] == s &&
arr[1][1] == s &&
arr[2][0] == s) {
reset("slant2", s);
}
if (friendTurn >= 9) reset("draw", "no one");
}
});
function reset(p, s) {
console.clear();
console.log(s, "win", p);
friendTurn = 0;
arr = [
[],
[],
[]
];
for (let td of document.querySelectorAll("td")) {
td.classList.remove("circle", "cross");
}
}
.cross {
background-image: url("https://via.placeholder.com/90/444/fff/?text=X");
background-size: cover;
}
.circle {
background-image: url("https://via.placeholder.com/90/bbb/000/?text=O");
background-size: cover;
}
table {
border-collapse: collapse;
width: 10em;
height: 10em;
margin: auto;
}
td {
border: 5px solid black;
}
<main>
<table class="delete">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</main>

Related

TicTacToe checkwin if statement does not go through even when conditions are met

<h1>TicTacToe!</h1>
<table>
<tr>
<td class="cell left"id="0"></td>
<td class="cell "id="1"></td>
<td class="cell"id="2"></td>
</tr>
<tr>
<td class="cell left"id="3"></td>
<td class="cell"id="4"></td>
<td class="cell"id="5"></td>
</tr>
<tr>
<td class="cell left"id="6"></td>
<td class="cell"id="7"> </td>
<td class="cell"id="8"></td>
</tr>
</table>
body {
font-family: system-ui;
background: #ffffff;
color: black;
text-align: center;
}
td {
border: 2px solid black;
height: 100px;
width: 100px;
cursor: pointer;
}
table {
margin-left: auto;
margin-right: auto;
border-collapse: collapse;
font-size: 20px;
}
table tr:first-child td {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child {
border-left: 0;
}
table tr td:last-child {
border-right: 0;
}
td:hover{background-color: #99e6ff ;opacity: 0.3;}
cells = document.querySelectorAll('.cell');
player = "X";
ai = "O";
function startgame(){
console.log(cells[2].innerText);
for (var i = 0; i < 9; i++){
cells[i].innerText = "";
cells[i].addEventListener("click",add_text);
}
}
function add_text(cell){
document.getElementById(cell.target.id).innerText = player;
if(checkwin()){
console.log("Game over");
}
}
function checkwin(){
for(var i = 0; i < 7; i+=3){
console.log("i",cells[i].innerText);
console.log("i 1 ",cells[i+1].innerText);
console.log("i 2",cells[i+2].innerText);
console.log(player);
if(cells[i].innerText == cells[i+1].innerText == cells[i+2].innerText == player){
console.log("S");
return True;
}
for(i = 0; i < 3; i++){
if(cells[i].innerText == cells[i+3].innerText == cells[i+6].innerText == player){
console.log("S");
return True;
}
}
for(i = 0; i < 3; i+=2) {
if(cells[i].innerText == cells[5].innerText == cells[i+6].innerText == player){
console.log("S");
return True;
}
}
}
}
startgame();
You might be able to access the pen with this link https://codepen.io/mark3334/pen/WNjXoOL?editors=0011. I don't understand why the check win function doesn't work. After clicking on the table the script does console.log on the innertext and it all shows up as "X" yet the if statement doesn't go through. Also for the event listener I don't get why there's no brackets I heard that for events you're not supposed to and something to do with calling a function and referencing the object but I don't really get it.
I see two basic problems:
Your inner loops are reusing i, which will prevent the outer loop from running through all desired values of i.
Your comparisons are wrong, e.g.:
if(cells[i].innerText == cells[5].innerText == cells[i+6].innerText == player){
This evaluates to:
if(((cells[i].innerText == cells[5].innerText) == cells[i+6].innerText ) == player){
The first expression (cells[i].innerText == cells[5].innerText) evaluates to a Boolean (true or false), which is then compared to a string (cells[i+6].innerText), which gives you an erroneous result.
Instead, to compare multiple values you must create multiple comparisons and join them with && (logical "and"):
if(
cells[i].innerText == cells[5].innerText
&&
cells[i].innerText == cells[i+6].innerText
&&
cells[i].innerText== player
){
You'll need to make this change to all three comparisons.

How to add a number dynamically with Javascript to the first cell

I'm learning Javascript and i'm stuck at the moment. When the user input their first name, last name, age and clicks on the button "add", 1 new row and 4 new cells are being added to the table with the value of the users input.
My question is: how do I get the first cell to be a number? Which in this case should be number 4. If the user adds another row with value it should become number 5. etc.
If somebody could point me in a direction or show me another way to do it, that would help. Thanks! (css added just for visuals)
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var formulier = allID("invoerformulier");
var nieuweGegevens = [];
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i] = formulier.elements[i].value;
}
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
}
}
var row = document.getElementsByClassName("rownmr");
var i = 0;
for (i = 0; i < row.length; i++) {
row[i].innerHTML = i + 1;
}
table,
th,
td {
border-collapse: collapse;
border: 1px solid black;
}
th,
td {
padding: 5px;
}
th {
text-align: left;
background-color: #c95050;
color: white;
}
.uitvoertabel {
width: 60%;
}
.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
.uitvoertabel tbody tr td:first-child {
width: 30px;
}
.invoerform {
margin-top: 50px;
width: 30%;
}
.invoerform input,
label {
display: block;
}
.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
#voegdatatoe {
margin-top: 30px;
}
input:focus {
border: 1px solid #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr"></td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
There are a number of ways you could store this information, from a global variable (not recommended) to some local closure, or even localStorage. But you have the information in the DOM, so it might be simplest to use it.
One way to do this would be to scan the ids, find their maximum, and add one to it. This involves a few changes to your code. First, we would add some code to scan your id cells for the largest value:
var rows = document.getElementsByClassName("rownmr");
var highestId = Math.max(...([...rows].map(row => Number(row.textContent))))
Then we would start your content array with a new value one higher than that maximum:
var nieuweGegevens = [highestId + 1];
And your loop needs to take this into account by adding one to the index
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i + 1] = formulier.elements[i].value;
}
Finally, we need to add the right class to that new cell so that on the next call, it will continue to work:
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
if (i === 0) { /**** new ****/
NieuweCell.classList.add("rownmr") /**** new ****/
} /**** new ****/
}
You can see these changes inline in this snippet:
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var formulier = allID("invoerformulier");
var rows = document.getElementsByClassName("rownmr");
var highestId = Math.max(...([...rows].map(row => Number(row.textContent))))
var nieuweGegevens = [highestId + 1];
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i + 1] = formulier.elements[i].value;
}
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
if (i === 0) {
NieuweCell.classList.add("rownmr")
}
}
}
var row = document.getElementsByClassName("rownmr");
var i = 0;
for (i = 0; i < row.length; i++) {
row[i].innerHTML = i + 1;
}
table,
th,
td {
border-collapse: collapse;
border: 1px solid black;
}
th,
td {
padding: 5px;
}
th {
text-align: left;
background-color: #c95050;
color: white;
}
.uitvoertabel {
width: 60%;
}
.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
.uitvoertabel tbody tr td:first-child {
width: 30px;
}
.invoerform {
margin-top: 50px;
width: 30%;
}
.invoerform input,
label {
display: block;
}
.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
#voegdatatoe {
margin-top: 30px;
}
input:focus {
border: 1px solid #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr"></td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
Note that this will continue to work on subsequent adds.
Add additional the length+1 param in the arrays of data
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var row = document.getElementsByTagName("tr");
var formulier = allID("invoerformulier");
var nieuweGegevens = [];
nieuweGegevens.push(row.length) //length param for first column
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i+1] = formulier.elements[i].value; //saving values from i=1
}
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i);
NieuweCell.innerHTML = nieuweGegevens[i];
}
}
var row = document.getElementsByClassName("rownmr");
var i = 0;
for (i = 0; i < row.length; i++) {
row[i].innerHTML = i + 1;
}
table,
th,
td {
border-collapse: collapse;
border: 1px solid black;
}
th,
td {
padding: 5px;
}
th {
text-align: left;
background-color: #c95050;
color: white;
}
.uitvoertabel {
width: 60%;
}
.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
.uitvoertabel tbody tr td:first-child {
width: 30px;
}
.invoerform {
margin-top: 50px;
width: 30%;
}
.invoerform input,
label {
display: block;
}
.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
#voegdatatoe {
margin-top: 30px;
}
input:focus {
border: 1px solid #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr"></td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr"></td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
As I note that none of the answers made, does not seem to have the approval of Niekket (no validation for anybody),
and that the question asked is accompanied by a very rough example (the author admits to being bloked in his apprenticeship), using a lot of useless code...
So I propose this complete solution, which I hope is enlightening enough on the proper way of coding its problem ( imho ).
const
TableBody_uitvoertabel = document.querySelector('#uitvoertabel > tbody'),
form_invoerformulier = document.querySelector('#invoerformulier'),
in_voornaam = document.querySelector('#voornaam'),
in_achternaam = document.querySelector('#achternaam'),
in_leeftijd = document.querySelector('#leeftijd')
;
var
RowCount = 0; // global..
// place numbers in the first column
document.querySelectorAll('#uitvoertabel > tbody > tr td:first-child').forEach(
elmTR=>{ elmTR.textContent = ++RowCount }
);
form_invoerformulier.onsubmit = function(e) {
e.preventDefault();
let
column = 0,
row = TableBody_uitvoertabel.insertRow(-1)
;
row.insertCell(column++).textContent = ++RowCount;
row.insertCell(column++).textContent = in_voornaam.value;
row.insertCell(column++).textContent = in_achternaam.value;
row.insertCell(column++).textContent = in_leeftijd.value;
this.reset();
}
table, th, td {
border-collapse: collapse;
border: 1px solid black;
}
th, td { padding: 5px; }
th {
text-align: left;
background-color: #c95050;
color: white;
}
table.uitvoertabel { width: 60%; }
table.uitvoertabel tr:nth-child(even) {
background-color: #eee;
}
table.uitvoertabel tbody tr td:first-child {
width: 30px;
}
form.invoerform {
margin-top: 50px;
width: 30%;
}
form.invoerform input,
form.invoerform label {
display: block;
}
form.invoerform label {
margin-bottom: 5px;
margin-top: 10px;
}
form.invoerform button {
margin-top: 30px;
}
form.invoerform input:focus {
border-color: #d45757;
outline: none;
}
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th><th>Voornaam</th><th>Achternaam</th><th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td></td><td>Johan</td><td>cruijff</td><td>54</td>
</tr>
<tr>
<td></td><td>Frans</td><td>Bauer</td><td>47</td>
</tr>
<tr>
<td></td><td>Willem</td><td>van Oranje</td><td>80</td>
</tr>
</tbody>
</table>
<form id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
<button type="submit">Voeg toe</button>
<button type="reset">Reset</button>
</form>
I think that the main issue is that you only manually set the rownmrs for the first time from line var row = document.getElementsByClassName("rownmr");
rather than every time you click on the "Voeg toe" button.
Ideally, for your hard coded numbers, they would be in the markup and the logic to grab the next rownmr to display and the adding of that cell happens on click.
html
<table class="uitvoertabel" id="uitvoertabel">
<thead>
<tr>
<th></th>
<th>Voornaam</th>
<th>Achternaam</th>
<th>Leeftijd</th>
</tr>
</thead>
<tbody>
<tr>
<td class="rownmr">1</td>
<td>Johan</td>
<td>cruijff</td>
<td>54</td>
</tr>
<tr>
<td class="rownmr">2</td>
<td>Frans</td>
<td>Bauer</td>
<td>47</td>
</tr>
<tr>
<td class="rownmr">3</td>
<td>Willem</td>
<td>van Oranje</td>
<td>80</td>
</tr>
</tbody>
</table>
<form action="" id="invoerformulier" class="invoerform">
<label>Voornaam:</label>
<input type="text" name="vnaam" id="voornaam">
<label>Achternaam:</label>
<input type="text" name="anaam" id="achternaam">
<label>Leeftijd:</label>
<input type="text" name="points" id="leeftijd">
</form>
<button id="voegdatatoe">Voeg toe</button>
js
function allID(id) {
return document.getElementById(id);
}
function allEvents() {
allID("voegdatatoe").onclick = function () {
voegToeGegevens();
};
}
allEvents();
function voegToeGegevens() {
var formulier = allID("invoerformulier");
var nieuweGegevens = [];
for (var i = 0; i < formulier.length; i++) {
nieuweGegevens[i] = formulier.elements[i].value;
}
var allRownmrs = document.getElementsByClassName('rownmr');
var lastRownmr = allRownmrs[allRownmrs.length - 1].innerHTML;
var nextRownmr = parseInt(lastRownmr) + 1;
var uitvoertabel = allID("uitvoertabel");
var nieuweRij = uitvoertabel.insertRow(-1);
for (i = 0; i < 4; i++) {
var NieuweCell = nieuweRij.insertCell(i)
// you probably can refactor here
if (i === 0) {
NieuweCell.innerHTML = nextRownmr
} else {
NieuweCell.innerHTML = nieuweGegevens[i - 1];
}
}
}

How to addEventListener to table cells

I'want to add an eventListener to the table cells so each time a table cell is clicked to execute a function .
var getDaysInMonth = function (year, month) {
return new Date(year, month, 0).getDate();
}
var calendar = {
month: function () {
var d = new Date();
return d.getMonth() + this.nextMonth;
},
year: function () {
var y = new Date();
return y.getFullYear();
},
nextMonth: 1,
cellColor: 'white',
}
var loopTable = function () {
var daysInMonth = getDaysInMonth(calendar.year(), calendar.month());
var table = document.getElementById('myTable');
var rows = table.rows;
var l = 1;
var month = calendar.month();
var year = calendar.year();
var firstDay = new Date(year + "-" + month).getDay();
var currentDay = new Date().getDay();
var dayOfMonth = new Date().getDate();
for (let i = 1; i < rows.length; i++) {
if (rows[i] == rows[1]) {
var k = 1;
for (let j = firstDay; j < rows[i].cells.length; j++) {
if (k === dayOfMonth && calendar.nextMonth === 1) {
rows[i].cells[j].style.backgroundColor = calendar.cellColor;
}
if (k <= daysInMonth) {
rows[i].cells[j].innerHTML = k;
k++
}
}
} else {
for (let j = 0; j < rows[i].cells.length; j++) {
if (k === dayOfMonth && calendar.nextMonth === 1) {
rows[i].cells[j].style.backgroundColor = calendar.cellColor;
}
if (k <= daysInMonth) {
rows[i].cells[j].innerHTML = k;
k++
}
}
}
}
}
loopTable();
clickCell();
function monthTitle() {
var monthsArray = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.'];
monthNum = calendar.month();
var monthName = monthsArray[calendar.month() - 1] + '' + calendar.year();
var title = document.getElementById('calendarTitle');
var nextArrow = document.getElementById('nxt');
var leftArrow = document.getElementById('prev');
if (monthName === ('Dec.' + '' + calendar.year())){
xmas();
}
if (monthNum >= 12) {
nextArrow.className += ' inactiveLink';
} else if (monthNum <= 1) {
leftArrow.className += ' inactiveLink';
} else {
nextArrow.classList.remove('inactiveLink');
leftArrow.classList.remove('inactiveLink');
}
title.innerHTML = '';
var titleNode = document.createTextNode(monthName);
title.appendChild(titleNode);
}
monthTitle();
function nextMonth() {
clearTable();
calendar.nextMonth += 1;
monthTitle();
loopTable();
}
function previousMonth() {
clearTable();
calendar.nextMonth -= 1;
monthTitle();
loopTable();
}
function clearTable() {
var table = document.getElementById('myTable');
var rows = table.rows;
for (var i = 1; i < rows.length; i++) {
cells = rows[i].cells;
for (var j = 0; j < cells.length; j++) {
if (cells[j].innerHTML = '') {
cells[j].style.display = 'none';
}
cells[j].innerHTML = '';
cells[j].style.backgroundColor = '#D9534F';
cells[j].style.emptyCells = 'hide';
}
}
}
var next = document.getElementById('nxt');
var previous = document.getElementById('prev');
var table = document.getElementById('myTable');
var cell = table.rows;
next.addEventListener('click', nextMonth);
previous.addEventListener('click', previousMonth);
function clickCell() {
var row = document.getElementById('myTable').rows;
for (var i = 0; i < row.length; i++) {
for (var j = 0; j < row[i].cells.length; j++ ) {
row[i].cells[j].addEventListener('click', function(){
console.log('click');
})
}
}
}
clickCell();
body {
background-color: rgb(0, 121, 191);
}
table {
width: 50%;
background-color: #D9534F;
border: 1px solid white;
padding: 10px;
padding-bottom: 20px;
font-size: 25px;
border-radius: 25px;
position: relative;
margin: auto;
}
td {
border: 1px solid white;
text-align: center;
font-weight: 600;
font-size: 20px;
padding: 20px;
}
th {
height: 50px;
}
.calArrows {
text-decoration: none;
color: white;
font-size: 35px;
}
#nxt {
font-size: 30px;
position: absolute;
top: 0;
right: 25%
}
#prev {
font-size: 30px;
position: absolute;
top: 0;
left: 25%;
}
#calendarTitle {
font-family: 'Indie Flower', cursive;
font-weight: 600;
font-size: 25px;
color: white;
}
.inactiveLink {
cursor: not-allowed;
pointer-events: none;
}
#myTable {
empty-cells: hide;
}
.xmasDec {
width: 90%;
height: 70%;
position: absolute;
top: -10%;
left: 5%;
}
#calWraper {
position: relative;
}
#myCan {
position: absolute;
top: 0;
left: 10%;
width: 90%;
height: 70%;
opacity: 0, 5;
}
<body>
<canvas class="myCan" width="100" height="100"></canvas>
<div id="calWraper">
<table id="myTable">
<caption id="calendarTitle">Test</caption>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thur</th>
<th>Fri</th>
<th>Sat</th>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
<canvas id="myCan" width="200" height="200" style="background-color: transparent"></canvas>
<i class="fa fa-arrow-left" ></i>
<i class="fa fa-arrow-right" ></i>
</div>
</html>
I tried by creating a function that it will loop through rows and cells and add the eventListener to each . But it seems that its not working , its working on random instances which is really strange behavior . Here is the function i create:
function clickCell() {
var row = document.getElementById('myTable').rows;
for (var i = 0; i < row.length; i++) {
for (var j = 0; j < row[i].cells.length; j++ ) {
console.log(row[i].cells[j].innerHTML);
row[i].cells[j].addEventListener('click', function(){
console.log('click');
})
}
}
}
It seems your canvas is overlapping your table. Because of that td elements in your table are never clicked.
You will need to add CSS property pointer-events:none to your canvas.
#myCan {
...
pointer-events: none;
}
This way it won't block table from being clicked anymore.
You can also add event listeners to your cells way simpler:
document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", function() {
// Here, `this` refers to the element the event was hooked on
console.log("clicked")
}));
That creates a separate function for each cell; instead, you could share one function without losing any functionality:
function clickHandler() {
// Here, `this` refers to the element the event was hooked on
console.log("clicked")
}
document.querySelectorAll('#myTable td')
.forEach(e => e.addEventListener("click", clickHandler));
Some browsers still don't have forEach on the HTMLCollection returned by querySelectorAll, but it's easily polyfilled:
if (!HTMLCollection.prototype.forEach) {
Object.defineProperty(HTMLCollection.prototype, "forEach", {
value: Array.prototype.forEach
});
}
If you have to support truly obsolete browsers that don't have Array.prototype.forEach, see the polyfill on MDN.
This is a case for event delegation: Hook the click event on the table (or table body), not individual cells, and then determine which cell was clicked by looking at event.target and its ancestors.
Simplified example:
document.querySelector("#my-table tbody").addEventListener("click", function(event) {
var td = event.target;
while (td !== this && !td.matches("td")) {
td = td.parentNode;
}
if (td === this) {
console.log("No table cell found");
} else {
console.log(td.innerHTML);
}
});
Live Copy:
document.querySelector("#my-table tbody").addEventListener("click", function(event) {
var td = event.target;
while (td !== this && !td.matches("td")) {
td = td.parentNode;
}
if (td === this) {
console.log("No table cell found");
} else {
console.log(td.innerHTML);
}
});
table, td, th {
border: 1px solid #ddd;
}
table {
border-collapse: collapse;
}
td, th {
padding: 4px;
}
<table id="my-table">
<thead>
<tr>
<th>First</th>
<th>Last</th>
</tr>
</thead>
<tbody>
<tr>
<td>Joe</td>
<td>Bloggs</td>
</tr>
<tr>
<td>Muhammad</td>
<td>Abdul</td>
</tr>
<tr>
<td>Maria</td>
<td>Gonzales</td>
</tr>
</tbody>
</table>
Note that instead of the loop you could use the new (experimental) closest method on elements:
var td = event.target.closest("td");
...but A) It's still experimental, and B) It won't stop when it reaches the tbody, so in theory if you had nested tables, would find the wrong cell.
If you need to support browsers that don't have Element.prototype.matches, in this specific case you could use td.tagName !== "TD" instead of !td.matches("td") (note the capitalization).
Using only the DOM objects
Here's an example cell wise event listener added on an HTML table (TicTacToe). It can be achieved easily using 'this' keyword and 'querySelectorAll'
The logic is in the JavaScript file:
First, get all the cells by their 'tag' ("td") using 'querySelectorAll' and save it as a list
Add an event listener to each of the cells, and give a function name to do whatever you want
Inside the event listener function, using this keyword update the cell content, or call other functions or do whatever task you have to complete.
var cells = document.querySelectorAll("td");
for (var cell of cells) {
cell.addEventListener('click', marker)
}
function marker() {
if (this.textContent === 'X') {
this.innerHTML = "O";
} else if (this.textContent === 'O') {
this.innerHTML = " ";
} else {
this.innerHTML = "X";
}
}
td {
text-align: center;
font-size: 50px
}
table,
th,
td {
border: 2px solid black;
width: 300px;
height: 100px;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Tic Tac Toe</title>
</head>
<body>
<table id="ticTac">
<tbody>
<tr>
<td>. </td>
<td>. </td>
<td>. </td>
</tr>
<tr>
<td>. </td>
<td>. </td>
<td>. </td>
</tr>
<tr>
<td>. </td>
<td>. </td>
<td>. </td>
</tr>
</tbody>
</table>
</body>
</html>

Can't change colour of text with CSS in a table

I want to add colour style into <div> tags.
This only works when using property:
`background-color`: orange;
But I want it should be changed only text, not the background.
Like this:
`color`: orange;
In this demo, don't need Javascript still working.
My demo at here:
function firefoxFix() {
if ( /firefox/.test( window.navigator.userAgent.toLowerCase() ) ) {
var tds = document.getElementsByTagName( 'td' );
for( var index = 0; index < tds.length; index++ ) {
tds[index].innerHTML = '<div class="ff-fix">' + tds[index].innerHTML + '</div>';
};
var style = '<style>'
+ 'td { padding: 0 !important; }'
+ 'td:hover::before, td:hover::after { background-color: transparent !important; }'
+ '</style>';
document.head.insertAdjacentHTML( 'beforeEnd', style );
};
};
firefoxFix();
table {
border-spacing: 0;
border-collapse: collapse;
overflow: hidden;
z-index: 1;
}
td, th, .ff-fix {
cursor: pointer;
padding: 10px;
position: relative;
}
td:hover::after,
.ff-fix:hover::after {
background-color: orange;
content: '\00a0';
height: 10000px;
left: 0;
position: absolute;
top: -5000px;
width: 100%;
z-index: -1;
}
<table>
<tbody>
<tr>
<td>20</td><td>21</td><td>23</td><td>25</td><td>27</td>
</tr>
<tr>
<td>18</td><td>20</td><td>22</td><td>24</td><td>26</td>
</tr>
<tr>
<td>17</td><td>19</td><td>21</td><td>23</td><td>25</td>
</tr>
<tr>
<td>16</td><td>18</td><td>20</td><td>22</td><td>24</td>
</tr>
</tbody>
</table>
Thanks.
The better approach I think, is to add class to html element when user is using firefox. You may use anonymous function for that, for example:
(function(html) {
if ( /firefox/.test( window.navigator.userAgent.toLowerCase() ) ) {
html.classList.add('is-firefox');
}
})(document.documentElement);
Then you can add css for that class:
.is-firefox td {
color: orange;
}
Working jsFiddle. Tested in Chrome 54 & Firefox 45.
You can try also this css fix without any javascript, like that:
#-moz-document url-prefix() {
td {
color: orange;
}
}
Here you have some more information about CSS hacks:
https://www.wired.com/2010/02/browser-specific_css_hacks/
You can add a className to all td elements at event.target .cellIndex at mouseover event, remove the className from all td elements at mouseleave event
var elems = document.querySelectorAll("td");
var elemParents = document.querySelectorAll("tr")
for (var td of elems) {
td.addEventListener("mouseover", function(e) {
var index = e.target.cellIndex;
for (let tr of elemParents) {
tr.querySelectorAll("td")[index]
.className = "color";
}
});
td.addEventListener("mouseleave", function(e) {
for (let tr of elemParents) {
for (var cell of tr.querySelectorAll("td")) {
cell.className = "";
}
}
})
}
function firefoxFix() {
if (/firefox/.test(window.navigator.userAgent.toLowerCase())) {
var tds = document.getElementsByTagName('td');
for (var index = 0; index < tds.length; index++) {
tds[index].innerHTML = '<div class="ff-fix">' + tds[index].innerHTML + '</div>';
};
var style = '<style>' + 'td { padding: 0 !important; }' + 'td:hover::before, td:hover::after { background-color: transparent !important; }' + '</style>';
document.head.insertAdjacentHTML('beforeEnd', style);
};
};
firefoxFix();
.color {
color: orange;
}
table {
border-spacing: 0;
border-collapse: collapse;
overflow: hidden;
z-index: 1;
}
td,
th,
.ff-fix {
cursor: pointer;
padding: 10px;
position: relative;
}
td:hover::after,
.ff-fix:hover::after {
background-color: blue;
content: '\00a0';
height: 10000px;
left: 0;
position: absolute;
top: -5000px;
width: 100%;
z-index: -1;
}
<table>
<tbody>
<tr>
<td>20</td>
<td>21</td>
<td>23</td>
<td>25</td>
<td>27</td>
</tr>
<tr>
<td>18</td>
<td>20</td>
<td>22</td>
<td>24</td>
<td>26</td>
</tr>
<tr>
<td>17</td>
<td>19</td>
<td>21</td>
<td>23</td>
<td>25</td>
</tr>
<tr>
<td>16</td>
<td>18</td>
<td>20</td>
<td>22</td>
<td>24</td>
</tr>
</tbody>
</table>
Hello Try This One Below
$('td').hover(function() {
var t = parseInt($(this).index()) + 1;
$('td:nth-child(' + t + ')').addClass('highlighted');
},
function() {
var t = parseInt($(this).index()) + 1;
$('td:nth-child(' + t + ')').removeClass('highlighted');
});
table, td {
border: 1px solid black;
}
td {
width: 40px;
height: 40px;
}
.highlighted {
color:orange;
background-color:black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>aa</td>
<td>aa</td>
<td>aa</td>
<td>aa</td>
</tr>
<tr>
<td>aa</td>
<td>aa</td>
<td>aa</td>
<td>aa</td>
</tr>
<tr>
<td>aa</td>
<td>aa</td>
<td>aa</td>
<td>aa</td>
</tr>
<tr>
<td>aa</td>
<td>aa</td>
<td>aa</td>
<td>aa</td>
</tr>
</table>
You can call function on every cell hover like this :
function a(ele){ //On mouse over
ele.style.color = 'orange';
}
function b(ele){ // On mouse out
ele.style.color = 'grey';
}

How to connect rows from different tables

I have two tables and I need to allow the user to connect rows from one table with rows from another, such as:
and later when the user clicks on submit button, I need the information about those connections in such a way:
[
{left: "Pera Lozac", right: "Eve Jakson"},
{left: "Mika Mikic", right: "Jill Smmith"},
{left: "Zika Zivac", right: "Joh Doe"},
{left: "Dezurni Krivac", right: "Joh Doe"},
]
How should I go about this using HTML/Javascript ?
Check my snippet below
Usage : select(click) any number of rows from the left table and select one row from the right table, then click Add Connection, the connection is then added and displayed below on the page in the form of a javascript object.
Note : Selected rows are highlighted in grey and the highlighting is removed when that row is unselected.
Snippet
$(document).ready(function() {
var temp_color = '#dddddd';
$('tr').on('click', function() {
current_background = $(this).css('background-color');
$(this).toggleClass('selected');
if ($(this).hasClass('selected')) {
$(this).css('background-color', temp_color);
} else {
$(this).css('background-color', '#fff');
}
});
$('#add_conn').on('click', function() {
var left = [];
var right = [];
$('tr').filter(function() {
var match = 'rgb(255,255,255)';
var this_element = $(this).css('background-color');
if (hexc(this_element) != hexc(match)) {
$(this).css('background-color', '#ffffff');
$(this).toggleClass('selected');
var count = 0;
var string_test = "";
$(this).find('td').each(function() {
if (count < 2) {
string_test += " " + $(this).text();
}
count++;
});
if ($(this).closest('div').attr('id') == "one") {
left.push(string_test.trim());
} else if ($(this).closest('div').attr('id') == "two") {
right.push(string_test.trim());
}
}
});
var temp = $('#message').html();
var arr = [];
for (l = 0; l < left.length; l++) {
arr.push({
left: left[l],
right: right[0]
});
}
temp = temp + JSON.stringify(arr);
$('#message').html(temp);
});
});
function hexc(colorval) {
var parts = colorval.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
delete(parts[0]);
for (var i = 1; i <= 3; ++i) {
parts[i] = parseInt(parts[i]).toString(16);
if (parts[i].length == 1) parts[i] = '0' + parts[i];
}
color = '#' + parts.join('');
return color;
}
#one {
position: absolute;
top: 10%;
left: 1%;
}
#two {
position: absolute;
top: 10%;
right: 35%;
}
table {
overflow: hidden;
}
tr {
background-color: #ffffff;
}
td {
padding: 10px;
position: relative;
outline: 0;
}
body:not(.nohover) tbody tr:hover {
background-color: #ffa;
}
.selected-bg-red {
background-color: red;
}
.selected-bg-green {
background-color: green;
}
#message {
position: absolute;
bottom: 10%;
left: 70%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="submit" id="add_conn" value="Add This Connection" />
<div id="one">
<table border="1">
<tr>
<td>Pera</td>
<td>Lozac</td>
<td>11</td>
</tr>
<tr>
<td>Mika</td>
<td>Mikic</td>
<td>22</td>
</tr>
<tr>
<td>Zika</td>
<td>Zivac</td>
<td>33</td>
</tr>
<tr>
<td>Dezurni</td>
<td>Krivac</td>
<td>44</td>
</tr>
</table>
</div>
<div id="two">
<table border="1">
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
<td>80</td>
</tr>
</table>
</div>
<div id="message">
</div>
Check this working sample here : fiddle
Hope this helps!

Categories

Resources