I have a form that takes in a name without space and a phone number.
I managed to get the form and the error messages to work but I couldn't find a way to hide the syle of the error when there's no message in it. It does the job in hiding the other subsequent error messages but not the first one, I found this out through Chrome's debugging tool.
I've tried iterating through all elements to find a blank innerHTML and make the error style hidden, but it didn't work, it couldn't find it.
Is there a way? Here's the code:
window.onload = function () {
let form = document.getElementById("formDetails");
form.addEventListener("submit", function (event) {
let haltSubmission = false;
cleanPhoneError();
cleanNameError();
for (let i = 0; i < form.elements.length; i++) {
if (!nameCheck(form.elements[i])) {
haltSubmission = true;
} else if (!matchingPhone(form, form.elements[i])) {
haltSubmission = true;
} else if (!lengthOfPhone(form.elements[i])) {
haltSubmission = true;
}
}
if (haltSubmission) {
event.preventDefault();
}
}, false);
}
function nameCheck(formInput) {
if (formInput.id === "name") {
let value = formInput.value, error = "", letters = /^[a-zA-Z]+$/,
characters = /^[a-zA-Z0-9!##\$%\^\&*\)\(+=._-]+$/g;
if (value === null || value === "") {
error = "This field is empty.";
}
if (value !== "") {
if (value.length < 3) {
error = "This field has less than 3 characters.";
}
if (!value.match(letters)) {
error = "Numbers detected. Please write your first name.";
}
if (!value.match(characters)) {
error = "Special characters detected. Please write your first name.";
}
}
errorMessage(formInput, error);
}
return true;
}
function matchingPhone(form, formInput) {
if (formInput.id === "phone") {
let error = "";
let phone = form.phone.value;
let retypedPhone = form.retypedphone.value;
if (phone === retypedPhone) {
return true;
} else {
error = "Phone numbers do not match.";
phoneError(error);
return false;
}
}
return true;
}
function lengthOfPhone(formInput) {
if (formInput.id === "phone") {
let value = formInput.value, error = "";
if (value === null || value === "") {
error = "This field is empty.";
phoneError(error);
return false;
} else if (value !== "") {
if (value.length < 11) {
error = "Invalid phone number, it has than 11 numbers.";
phoneError(error);
return false;
}
}
}
return true;
}
function errorMessage(selected, error) {
let elem = document.createElement("span");
elem.setAttribute("id", "nameError");
elem.setAttribute("class", "error");
let text = document.createTextNode(error);
elem.appendChild(text);
selected.parentNode.insertBefore(elem, selected.nextSibling);
return selected;
}
function phoneError(error) {
let phoneError = document.getElementById("phoneError");
phoneError.setAttribute("class", "error");
phoneError.innerHTML = error;
}
function cleanPhoneError() {
let error = document.getElementsByTagName("span");
for (let i = 0; i < error.length; i++) {
error[i].innerHTML = "";
}
}
function cleanNameError() {
let error = document.getElementById("nameError");
let errorMessage = document.getElementsByTagName("span");
for (let i = 0; i < errorMessage.length; i++) {
if (errorMessage[i].id === "nameError") {
error.style.display = "none";
}
}
}
label, button {
display: block;
margin: 10px 0 5px 0;
}
input, button {
padding: 8px;
width: 393px;
font-size: 16px;
}
body, button{
font-family: Arial, sans-serif;
}
.error{
color: #FFF;
display: block;
margin: 0 0 15px 0;
background: #990000;
padding: 5px 3px 5px 5px;
width: 405px;
line-height: 25px;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript</title>
<link rel="stylesheet" href="css/test.css">
<script src="js/test.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<section>
<h1>Form</h1>
<div id="form">
<form id="formDetails" action="confirm.html">
<div>
<label for="name">* Name:</label>
<input type="text" id="name">
</div>
<div>
<label for="phone">* Phone Number</label>
<input type="phone" id="phone">
</div>
<div>
<label for="retypedphone">* Retype Phone Number:</label>
<input type="phone" id="retypedphone">
<span id="phoneError"></span>
</div>
<div>
<button type="submit" id="submitbtn">Submit</button>
</div>
</form>
</div>
</section>
</body>
</html>
You need to modify your function errorMessage(...) to only append the element if there is an error message.
A simple `if` statement might be enough for your needs.
UPDATE
Based on comment, I re-wrote the hiding/showing error logic, please have a look. I think this is a bit more readable too
See demo below
function cleanPhoneError() {
hideElement("phoneError");
}
function hideElement(elementName) {
let elementObj = document.getElementById(elementName);
if (elementObj) {
elementObj.innerHTML = "";
elementObj.setAttribute("class", "hidden");
}
}
window.onload = function() {
let form = document.getElementById("formDetails");
form.addEventListener("submit", function(event) {
let haltSubmission = false;
cleanErrors();
if (!validName()) {
haltSubmission = true;
}
if (!validPhone()) {
haltSubmission = true;
}
if (haltSubmission === true) {
event.preventDefault();
}
}, false);
}
function cleanErrors() {
cleanPhoneError();
cleanNameError();
}
function validName() {
let nameObj = document.getElementById("name");
if (nameObj) {
let value = nameObj.value,
error = "",
letters = /^[a-zA-Z]+$/,
numbers = /[0-9]+/,
characters = /[!##\$%\^\&*\)\(+=._-]+/g;
if (value === null || value === "") {
error = "This field is empty.";
} else if (value.length < 3) {
error = "This field has less than 3 characters.";
} else if (value.match(characters)) {
error = "Special characters detected. Please write your first name.";
} else if (value.match(numbers)) {
error = "Numbers detected. Please write your first name.";
}
if (error !== undefined && error.trim() !== '') {
displayErrorMessage(error, "nameError");
return false;
}
return true;
}
displayErrorMessage("Unable to find Name field.", "nameError");
return false;
}
function validPhone() {
let phoneObj = document.getElementById("phone");
let retypedPhoneObj = document.getElementById("retypedPhone");
if (phoneObj && retypedPhoneObj) {
let phoneValue = phoneObj.value;
let retypedPhoneValue = retypedPhoneObj.value;
if (phoneValue !== retypedPhoneValue) {
displayErrorMessage("Phone numbers do not match.", "phoneError");
return false;
} else {
return validateLengthOfPhone(phoneValue);
}
} else {
displayErrorMessage("Unable to find Phone fields.", "phoneError");
return false;
}
return true;
}
function validateLengthOfPhone(value) {
let error = "";
if (value === null || value === "") {
error = "This field is empty.";
displayErrorMessage(error, "phoneError");
return false;
} else if (value.length < 11) {
error = "Invalid phone number, it has less than 11 numbers.";
displayErrorMessage(error, "phoneError");
return false;
}
return true;
}
function displayErrorMessage(errorMsg, elementName) {
if (errorMsg !== undefined && errorMsg.trim() !== '') {
let elementError = document.getElementById(elementName);
elementError.setAttribute("class", "error visible");
elementError.innerHTML = errorMsg;
}
}
function cleanPhoneError() {
hideElement("phoneError");
}
function cleanNameError() {
hideElement("nameError");
}
function hideElement(elementName) {
let elementObj = document.getElementById(elementName);
if (elementObj) {
elementObj.innerHTML = "";
elementObj.setAttribute("class", "hidden");
}
}
label,
button {
display: block;
margin: 10px 0 5px 0;
}
input,
button {
padding: 8px;
width: 393px;
font-size: 16px;
}
body,
button {
font-family: Arial, sans-serif;
}
.error {
color: #FFF;
display: block;
margin: 0 0 15px 0;
background: #990000;
padding: 5px 3px 5px 5px;
width: 405px;
line-height: 25px;
display: none;
}
.visible {
display: inline-block;
}
.hidden {
display: none;
}
<section>
<h1>Form</h1>
<div id="form">
<form id="formDetails" action="confirm.html">
<div>
<label for="name">* Name:</label>
<input type="text" id="name">
<span id="nameError" class="error"></span>
</div>
<div>
<label for="phone">* Phone Number</label>
<input type="phone" id="phone">
</div>
<div>
<label for="retypedphone">* Retype Phone Number:</label>
<input type="phone" id="retypedPhone">
<span id="phoneError" class="error"></span>
</div>
<div>
<button type="submit" id="submitbtn">Submit</button>
</div>
</form>
</div>
</section>
Related
Say a user has a HTML file, and they are using a touchscreen device, say a phone.
I have this set of code right here:
W.onmousedown = function () {
gameOver();
}
Basically what it does is detect if the div named W was clicked and if so, end the game.
I want to do this same thing but instead, it's detecting if the user touched the DIV on their screen. How can I do this?
Edit:
Using click for me doesn't work, it doesn't end the game. This is my code:
var gameIsPlaying = true;
function game() {
gameIsPlaying = true;
const RandomLetterGUI = document.getElementById("RandomLetters")
const TimerGUI = document.getElementById("Timer")
const LivesGUI = document.getElementById("Lives")
const ScoreGUI = document.getElementById("Score")
const W = document.getElementById("W")
const A = document.getElementById("A")
const S = document.getElementById("S")
const D = document.getElementById("D")
W.style.backgroundColor = "white";
W.innerHTML = 'W'
A.style.backgroundColor = "white";
A.innerHTML = 'A'
S.style.backgroundColor = "white";
S.innerHTML = 'S'
D.style.backgroundColor = "white";
D.innerHTML = 'D'
const letters = [
"W",
"A",
"S",
"D"
]
var seconds = 60;
var lives = 3;
var score = 0;
var timerId = setInterval(countdown, 1000);
function countdown() {
if (seconds == -1) {
gameOver()
} else {
if (seconds > 9) {
TimerGUI.innerHTML = ':' + seconds;
} else {
TimerGUI.innerHTML = ':0' + seconds;
}
seconds--;
}
}
countdown()
const updateLives = setInterval(displayLives, 0)
const ScoreUpdate = setInterval(updateScore, 0)
function gameOver() {
gameIsPlaying = false
clearTimeout(timerId)
clearTimeout(updateLives)
clearTimeout(ScoreUpdate)
W.style.backgroundColor = "red";
W.innerHTML = ''
A.style.backgroundColor = "red";
A.innerHTML = ''
S.style.backgroundColor = "red";
S.innerHTML = ''
D.style.backgroundColor = "red";
D.innerHTML = ''
RandomLetterGUI.innerHTML = ''
TimerGUI.innerHTML = ''
LivesGUI.innerHTML = ''
ScoreGUI.innerHTML = ''
}
function updateScore() {
ScoreGUI.innerHTML = "Score: " + score
}
function displayLives() {
LivesGUI.innerHTML = "Remaining Lives: " + lives
if (lives == 0) {
gameOver()
}
}
function letter() {
var item = letters[Math.floor(Math.random() * letters.length)];
RandomLetterGUI.innerHTML = "Next Letter: " + item
var pickedLetterTime = Math.floor(Date.now() / 1000)
document.onkeypress = function(e) {
if (gameIsPlaying) {
var key = e.key
if (key.toUpperCase() != item) {
lives -= 1;
if (score >= 0) {
score -= 50;
}
} else {
var pressedKeyTime = Math.floor(Date.now() / 1000)
var seconds = pressedKeyTime - pickedLetterTime
if (seconds > 0 && seconds < 1.5) {
score += 500
}
if (seconds >= 1.5 && seconds < 3) {
score += 350
}
if (seconds >= 3 && seconds < 5) {
score += 150
}
}
}
};
document.onkeydown = function(e) {
var key = e.key
if (key == "w") {
W.style.backgroundColor = "lime";
W.innerHTML = ''
}
if (key == "a") {
A.style.backgroundColor = "lime";
A.innerHTML = ''
}
if (key == "s") {
S.style.backgroundColor = "lime";
S.innerHTML = ''
}
if (key == "d") {
D.style.backgroundColor = "lime";
D.innerHTML = ''
}
}
document.onkeyup = function(e) {
if (e.key == "w") {
W.style.backgroundColor = "white";
W.innerHTML = 'W'
}
if (e.key == "a") {
A.style.backgroundColor = "white";
A.innerHTML = 'A'
}
if (e.key == "s") {
S.style.backgroundColor = "white";
S.innerHTML = 'S'
}
if (e.key == "d") {
D.style.backgroundColor = "white";
D.innerHTML = 'D'
}
}
// touchscreen compatibility
W.onclick = function() {
gameOver();
}
}
letter()
}
game()
function resetGame() {
if (gameIsPlaying == false) {
document.onkeypress = function(e) {
var key = e.key
if (key == "Enter") {
game()
}
}
}
}
setInterval(resetGame, 0)
body {
background-color: black;
}
p {
font-family: Verdana;
color: white;
font-size: 20px;
}
.RandomLetters {
float: left;
}
.Timer {
float: right;
}
.Lives {
position: absolute;
left: auto;
}
.Score {
position: absolute;
right: 0;
}
.center {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
bottom: 100px;
left: 0;
right: 0;
margin: auto;
}
.center2 {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.W,
.A,
.S,
.D {
height: 50px;
width: 50px;
font-family: Verdana;
text-align: center;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Play WASD online</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<noscript>turn on javascript to play this game or noob :P</noscript>
<p id="RandomLetters" class="RandomLetters">
</p>
<p id="Timer" class="Timer">
</p>
<br>
<p id="Lives" class="Lives">
</p>
<p id="Score" class="Score">
</p>
<div class="center">
<div id="W" class="W">
</div>
</div>
<div class="center2">
<div id="A" class="A">
</div>
<div id="S" class="S">
</div>
<div id="D" class="D">
</div>
</div>
<script src="script.js"></script>
</body>
</html>
It doesn't work, because you obscured your W container with another one and it's not clickable
I changed the order of containers so the W one is now at the front layer and it works
var gameIsPlaying = true;
function game() {
gameIsPlaying = true;
const RandomLetterGUI = document.getElementById("RandomLetters")
const TimerGUI = document.getElementById("Timer")
const LivesGUI = document.getElementById("Lives")
const ScoreGUI = document.getElementById("Score")
const W = document.getElementById("W")
const A = document.getElementById("A")
const S = document.getElementById("S")
const D = document.getElementById("D")
W.style.backgroundColor = "white";
W.innerHTML = 'W'
A.style.backgroundColor = "white";
A.innerHTML = 'A'
S.style.backgroundColor = "white";
S.innerHTML = 'S'
D.style.backgroundColor = "white";
D.innerHTML = 'D'
const letters = [
"W",
"A",
"S",
"D"
]
var seconds = 60;
var lives = 3;
var score = 0;
var timerId = setInterval(countdown, 1000);
function countdown() {
if (seconds == -1) {
gameOver()
} else {
if (seconds > 9) {
TimerGUI.innerHTML = ':' + seconds;
} else {
TimerGUI.innerHTML = ':0' + seconds;
}
seconds--;
}
}
countdown()
const updateLives = setInterval(displayLives, 0)
const ScoreUpdate = setInterval(updateScore, 0)
function gameOver() {
gameIsPlaying = false
clearTimeout(timerId)
clearTimeout(updateLives)
clearTimeout(ScoreUpdate)
W.style.backgroundColor = "red";
W.innerHTML = ''
A.style.backgroundColor = "red";
A.innerHTML = ''
S.style.backgroundColor = "red";
S.innerHTML = ''
D.style.backgroundColor = "red";
D.innerHTML = ''
RandomLetterGUI.innerHTML = ''
TimerGUI.innerHTML = ''
LivesGUI.innerHTML = ''
ScoreGUI.innerHTML = ''
}
function updateScore() {
ScoreGUI.innerHTML = "Score: " + score
}
function displayLives() {
LivesGUI.innerHTML = "Remaining Lives: " + lives
if (lives == 0) {
gameOver()
}
}
function letter() {
var item = letters[Math.floor(Math.random() * letters.length)];
RandomLetterGUI.innerHTML = "Next Letter: " + item
var pickedLetterTime = Math.floor(Date.now() / 1000)
document.onkeypress = function(e) {
if (gameIsPlaying) {
var key = e.key
if (key.toUpperCase() != item) {
lives -= 1;
if (score >= 0) {
score -= 50;
}
} else {
var pressedKeyTime = Math.floor(Date.now() / 1000)
var seconds = pressedKeyTime - pickedLetterTime
if (seconds > 0 && seconds < 1.5) {
score += 500
}
if (seconds >= 1.5 && seconds < 3) {
score += 350
}
if (seconds >= 3 && seconds < 5) {
score += 150
}
}
}
};
document.onkeydown = function(e) {
var key = e.key
if (key == "w") {
W.style.backgroundColor = "lime";
W.innerHTML = ''
}
if (key == "a") {
A.style.backgroundColor = "lime";
A.innerHTML = ''
}
if (key == "s") {
S.style.backgroundColor = "lime";
S.innerHTML = ''
}
if (key == "d") {
D.style.backgroundColor = "lime";
D.innerHTML = ''
}
}
document.onkeyup = function(e) {
if (e.key == "w") {
W.style.backgroundColor = "white";
W.innerHTML = 'W'
}
if (e.key == "a") {
A.style.backgroundColor = "white";
A.innerHTML = 'A'
}
if (e.key == "s") {
S.style.backgroundColor = "white";
S.innerHTML = 'S'
}
if (e.key == "d") {
D.style.backgroundColor = "white";
D.innerHTML = 'D'
}
}
// touchscreen compatibility
W.onclick = function() {
gameOver();
}
}
letter()
}
game()
function resetGame() {
if (gameIsPlaying == false) {
document.onkeypress = function(e) {
var key = e.key
if (key == "Enter") {
game()
}
}
}
}
setInterval(resetGame, 0)
body {
background-color: black;
}
p {
font-family: Verdana;
color: white;
font-size: 20px;
}
.RandomLetters {
float: left;
}
.Timer {
float: right;
}
.Lives {
position: absolute;
left: auto;
}
.Score {
position: absolute;
right: 0;
}
.center {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
bottom: 100px;
left: 0;
right: 0;
margin: auto;
}
.center2 {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.W,
.A,
.S,
.D {
height: 50px;
width: 50px;
font-family: Verdana;
text-align: center;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Play WASD online</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<noscript>turn on javascript to play this game or noob :P</noscript>
<p id="RandomLetters" class="RandomLetters">
</p>
<p id="Timer" class="Timer">
</p>
<br>
<p id="Lives" class="Lives">
</p>
<p id="Score" class="Score">
</p>
<div class="center2">
<div id="A" class="A">
</div>
<div id="S" class="S">
</div>
<div id="D" class="D">
</div>
</div>
<div class="center">
<div id="W" class="W">
</div>
</div>
<script src="script.js"></script>
</body>
</html>
var element= document.getElementById("IDName");
element.onclick = function () {
gameOver();
}
you can use click or Pointer Events
You can use the touchstart event for this, see this mdn article
W.ontouchstart = function () {
gameOver();
}
I tried to create a tic-tac-toe game using minimax algorithm. But before I could write the whole algorithm, I encountered an absurd type of error. This code is for reference in case if you have to look into the full code.
//Using minimax to the same code of tictactoe2.js
$ = document.querySelectorAll(".box");
// adding click event to all boxes
$.forEach((element)=>{
element.addEventListener("click", mainFunction);
})
document.querySelector(".reset-button-container").addEventListener("click", reset);
function mainFunction(e){
if (checkForGameOver() === false){ //once game is over, so should be all clicks
if (e.target.innerText !== ""){
alert("Click Another Square!!!");
}
else{
e.target.innerText = "X";
if (checkForGameOver() === false){ //computer gets its turn only if the game isn't over after players turn
setTimeout(computerTurn, 500);
setTimeout(checkForGameOver, 501); //501 is provided to run checkForGameOver only after computerTurn
}
}
}
}
//a function that randomly plays computers turn
function computerTurn(){
let board = [], bestScore = Infinity, bestMove = {}, k = 0;
//array of innerTexts of each box is the board in one dimension
$.forEach((element, index) => {
board[index] = element.innerText;
});
let board2D = convertToTwoDimension(board, 3, 3); //convert 1d board to 2d of 3 rows and 3 columns
for(i = 0; i < 3; i++){
for(j = 0; j < 3; j++){
if (board2D[i][j] === ""){
board2D[i][j] = "O";
let score = minimax(board2D, false);
board2D[i][j] = "";
if(score < bestScore){
bestScore = score;
bestMove = {i, j};
}
}
}
}
board2D[bestMove.i][bestMove.j] = "O"; //assigning bestMove to baord2D
//to dispaly the played bestMove by the computer on screen
for(i = 0; i < 3; i++){
for(j = 0; j < 3; j++){
$[k].innerText = board2D[i][j];
k += 1;
}
}
}
//minimax implementation
function minimax(position, maximizing){
console.log(position);
//if the game is over at that position, return the score based on who is wining
if (checkForGameOver() === true){
if(document.querySelector(".win-message").innerText[0] === "X"){
return 1; //X (maximizing player) wins
}
else if(document.querySelector(".win-message").innerText[0] === "O"){
return -1; //O (minimizing player) wins
}
else{
return 0; // the game is a draw
}
}
}
//function to check if game is over. But I think it can be written more easily.
function checkForGameOver(){
var tempText = [];
for(i = 1; i <= 9; i++){
tempText[i] = $[i-1].innerText;
}
if (tempText[1] === tempText[2] && tempText[2] === tempText[3] && tempText[1] !== ""){
document.querySelector(".win-message").innerText = tempText[1] + " Wins!!";
return true;
}
else if (tempText[4] === tempText[5] && tempText[5] === tempText[6] && tempText[4] !== ""){
document.querySelector(".win-message").innerText = tempText[4] + " Wins!!";
return true;
}
else if (tempText[7] === tempText[8] && tempText[8] === tempText[9] && tempText[7] !== ""){
document.querySelector(".win-message").innerText = tempText[7] + " Wins!!";
return true;
}
else if (tempText[1] === tempText[4] && tempText[4] === tempText[7] && tempText[1] !== ""){
document.querySelector(".win-message").innerText = tempText[1] + " Wins!!";
return true;
}
else if (tempText[2] === tempText[5] && tempText[5] === tempText[8] && tempText[2] !== ""){
document.querySelector(".win-message").innerText = tempText[2] + " Wins!!";
return true;
}
else if (tempText[3] === tempText[6] && tempText[6] === tempText[9] && tempText[3] !== ""){
document.querySelector(".win-message").innerText = tempText[3] + " Wins!!";
return true;
}
else if (tempText[1] === tempText[5] && tempText[5] === tempText[9] && tempText[1] !== ""){
document.querySelector(".win-message").innerText = tempText[1] + " Wins!!";
return true;
}
else if (tempText[3] === tempText[5] && tempText[5] === tempText[7] && tempText[3] !== ""){
document.querySelector(".win-message").innerText = tempText[3] + " Wins!!";
return true;
}
//if none of above, which is for win only, is true, check for draw which can be done by filtering the remaining blank squares. If no squares are lest, then game is a draw else the game isn't over yet.
else{
arrayOfBlankCharacters = tempText.filter(element => {
return (element === "");
});
if (arrayOfBlankCharacters.length === 0){
document.querySelector(".win-message").innerText = "Game Drawn!!";
return true;
}
else{
return false;
}
}
}
//a function that resets the board and win message.
function reset(){
for(i = 1; i <= 9; i++){
$[i-1].innerText = "";
}
document.querySelector(".win-message").innerText = "";
}
//function to convert 1d array to 2d array => useful for computerTurn() function to access board in 2d view
function convertToTwoDimension(initialArray, rows, columns){
var k = 0, finalArray = [];
for(i = 0; i < initialArray.length/columns; i++){
finalArray[i] = []; //state that each element of finalArray is also an array
for(j = 0; j < initialArray.length/rows; j++){
finalArray[i][j] = initialArray[k];
k += 1;
}
}
return finalArray;
}
#import url('https://fonts.googleapis.com/css2?family=Roboto:wght#900&display=swap');
:root{
font-size: 16px;
font-family: 'Roboto', sans-serif;
}
*, *::after, *::before{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.description-header{
background-color: lightgrey;
line-height: 3rem;
padding-left: 2rem;
margin-bottom: 2rem;
}
.player-information{
text-align: center;
margin-bottom: 1rem;
}
.player-information > h3{
font-size: 2.5rem;
}
.player-information > h3 > span{
color:brown;
}
.game-box-container{
display: flex;
flex-direction: column;
min-height: 100vh;
align-items: center;
}
.tictactoe-box{
height: 250px;
width: 250px;
display: grid;
grid-template: repeat(3, 1fr)/repeat(3, 1fr);
grid-gap: 0.5rem;
background-color: black;
}
.reset-button-container{
margin-top: 1rem;
background: lightgrey;
border-radius: 0.5rem;
}
.tictactoe-box > .box{
display: flex;
justify-content: center;
align-items: center;
font-size: 4rem;
background-color: white;
cursor: context-menu
}
.reset-button-container > span{
display: block;
font-size: 2rem;
padding: 0.5rem 1.5rem;
}
.reset-button-container:hover{
background-color: grey;
cursor: context-menu;
}
.win-message{
margin-top: 1rem;
width: 25%;
font-size: 2.5rem;
background-color: lightgrey;
text-align: center;
border-radius: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>TicTacToe</title>
<link rel="stylesheet" type="text/css" href="tictactoe.css">
<link rel="icon" type="image/x-icon" href="https://upload.wikimedia.org/wikipedia/commons/thumb/3/32/Tic_tac_toe.svg/1024px-Tic_tac_toe.svg.png">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-sclae=1.0">
<meta name="description" content="">
<meta name="keywords" content="">
</head>
<body>
<header class="description-header">
<h3>My TicTacToe Game</h3>
</header>
<div class="player-information">
<h3>Player: "<span>X</span>"; Computer: "<span>O</span>"</h3>
<h3>Player First</h3>
</div>
<div class="game-box-container">
<div class="tictactoe-box">
<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
<div class="box box4"></div>
<div class="box box5"></div>
<div class="box box6"></div>
<div class="box box7"></div>
<div class="box box8"></div>
<div class="box box9"></div>
</div>
<div class="reset-button-container">
<span>Reset</span>
</div>
<div class="win-message">
</div>
</div>
<script type="text/javascript" src="usingMinimax.js"></script>
</body>
</html>
My problem arises in the minimax(position, maximizing) function of the code as below. console.log(position) runs just fine, but because of the checkForGameOver() in the below function, it throws an error that board2D[i] is undefined which is unexpected because there is no any arguments passed in to the checkForGameOver() function. As soon as I remove the (checkForGameOver() === false) condition and run it, the computer makes a move for the first available spot which is as expected.
//minimax implementation
function minimax(position, maximizing){
console.log(position);
//if the game is over at that position, return the score based on who is wining
if (checkForGameOver() === true){
if(document.querySelector(".win-message").innerText[0] === "X"){
return 1; //X (maximizing player) wins
}
else if(document.querySelector(".win-message").innerText[0] === "O"){
return -1; //O (minimizing player) wins
}
else{
return 0; // the game is a draw
}
}
}
A function that doesn't take any variable as arguments just returns a boolean value, is somehow the cause of an error that the variable is undefined.
I have created a form and with JS, if the value is " " or null, the bottom-border-color is changed to red. With input::placeholder {red} the text changes to red. Im trying to apply this if the value is " " or null. Is there a way to add this logic to my current JS code? Any tips are greatly appreciated! Thank you in advance.
form.addEventListener("submit", (e) => {
if (nameValue.value === "" || nameValue.value == null) {
nameError.innerText = "Please add your name!";
inputs[1].classList.add("invalid");
} else {
nameError.innerText = "";
}
if (companyValue.value === "" || companyValue.value == null) {
companyError.innerText = "Please add your companys name!";
inputs[2].classList.add("invalid");
} else {
companyError.innerText = "";
}
if (titleValue.value === "" || titleValue.value == null) {
titleError.innerText = "Please add your title!";
inputs[3].classList.add("invalid");
} else {
titleError.innerText = "";
}
if (messageValue.value === "" || messageValue.value == null) {
messageError.innerText = "Please leave a message!";
inputs[4].classList.add("invalid");
} else {
messageError.innerText = "";
}
if (emailValue.value === "" || emailValue == null) {
emailError.innerText = "Please add your email!";
inputs[5].classList.add("invalid");
} else {
emailError.innerText = "";
}
e.preventDefault();
});
Just create a parent class to affect and adjust your rules accordingly
function showDemo() {
document.querySelector('input[name="test"]').classList.toggle('invalid');
}
input{
padding:5px;
width:70%;
}
::placeholder{
color:#ccc;
}
.invalid::placeholder{
color:#f00;
}
<div class='form-control'>
<input name='test' placeholder="Don't type anything in here, just click the button"/>
</div>
<button onclick='showDemo()'>Test this (toggle) </button>
I'm a self taught programmer and I got my hands on a TicTacToe project, but I got stucked at the following part.
I did a relatively working TicTacToe(inspired from youtube) then I wanted to do a responsive TicTacToe matrix that changes it's numbers from(0-9) in X's and O's in the console depending of the inputs of the first game. But now I'm stuck at trying to find a way to check the winners of the matrix oh and I'm trying to start the "checking" from the last X or O
Hopefully seeing the code is much more easier to understand.
I'd really really appreciate some help!
const statusDiv = document.querySelector('.status');
const resetDiv = document.querySelector('.reset');
const cellDivs = document.querySelectorAll('.game-cell');
// game constants
const xSymbol = '×';
const oSymbol = '○';
// game variables
let gameIsLive = true;
let xIsNext = true;
var currentPlayer = 0;
//Random generated
function getInputValue() {
document.getElementById("formInput").style.display = "none";
document.getElementById("container").style.display = "inline";
let player1Input = document.getElementById("player1Input").value;
let player2Input = document.getElementById("player2Input").value;
currentPlayer = 1;
var random = Math.random() * 100;
if (random <= 60) {
currentPlayer = 1;
statusDiv.innerHTML = player1Input + " turn";
statusDiv.style.color = "blue";
}
else {
currentPlayer = 2;
statusDiv.innerHTML = player2Input + " turn";
statusDiv.style.color = "red";
}
}
// statusDiv.style.filter= "green";
//functions
const letterToSymbol = (letter) => letter === 'x' ? xSymbol : oSymbol;
const handleWin = (letter) => {
gameIsLive = false;
if (currentPlayer === 1) {
statusDiv.innerHTML = player1Input.value + " has won!";
statusDiv.style.color = "blue";
} else {
statusDiv.innerHTML = player2Input.value + " has won!";
statusDiv.style.color = "red";
}
};
const checkGameStatus = () => {
const topLeft = cellDivs[0].classList[1];
const topMiddle = cellDivs[1].classList[1];
const topRight = cellDivs[2].classList[1];
const middleLeft = cellDivs[3].classList[1];
const middleMiddle = cellDivs[4].classList[1];
const middleRight = cellDivs[5].classList[1];
const bottomLeft = cellDivs[6].classList[1];
const bottomMiddle = cellDivs[7].classList[1];
const bottomRight = cellDivs[8].classList[1];
// check winner
if (topLeft && topLeft === topMiddle && topLeft === topRight) {
handleWin(topLeft);
cellDivs[0].classList.add('won');
cellDivs[1].classList.add('won');
cellDivs[2].classList.add('won');
} else if (middleLeft && middleLeft === middleMiddle && middleLeft === middleRight) {
handleWin(middleLeft);
cellDivs[3].classList.add('won');
cellDivs[4].classList.add('won');
cellDivs[5].classList.add('won');
} else if (bottomLeft && bottomLeft === bottomMiddle && bottomLeft === bottomRight) {
handleWin(bottomLeft);
cellDivs[6].classList.add('won');
cellDivs[7].classList.add('won');
cellDivs[8].classList.add('won');
} else if (topLeft && topLeft === middleLeft && topLeft === bottomLeft) {
handleWin(topLeft);
cellDivs[0].classList.add('won');
cellDivs[3].classList.add('won');
cellDivs[6].classList.add('won');
} else if (topMiddle && topMiddle === middleMiddle && topMiddle === bottomMiddle) {
handleWin(topMiddle);
cellDivs[1].classList.add('won');
cellDivs[4].classList.add('won');
cellDivs[7].classList.add('won');
} else if (topRight && topRight === middleRight && topRight === bottomRight) {
handleWin(topRight);
cellDivs[2].classList.add('won');
cellDivs[5].classList.add('won');
cellDivs[8].classList.add('won');
} else if (topLeft && topLeft === middleMiddle && topLeft === bottomRight) {
handleWin(topLeft);
cellDivs[0].classList.add('won');
cellDivs[4].classList.add('won');
cellDivs[8].classList.add('won');
} else if (topRight && topRight === middleMiddle && topRight === bottomLeft) {
handleWin(topRight);
cellDivs[2].classList.add('won');
cellDivs[4].classList.add('won');
cellDivs[6].classList.add('won');
} else if (topLeft && topMiddle && topRight && middleLeft && middleMiddle && middleRight && bottomLeft && bottomMiddle && bottomRight) {
gameIsLive = false;
statusDiv.innerHTML = 'Game is tied!';
} else {
xIsNext = !xIsNext;
if (currentPlayer === 2) {
statusDiv.innerHTML = player1Input.value + ` turn`;
statusDiv.style.color = "blue";
currentPlayer = 1;
} else {
currentPlayer = 2;
statusDiv.style.color = "red";
statusDiv.innerHTML = player2Input.value + ` turn`;
}
}
};
// event Handlers
const handleReset = () => {
document.getElementById("formInput").style.display = "inline";
document.getElementById("container").style.display = "none";
xIsNext = true;
statusDiv.innerHTML = `Press Start Game`;
for (const cellDiv of cellDivs) {
cellDiv.classList.remove('x');
cellDiv.classList.remove('o');
cellDiv.classList.remove('won');
document.location.reload()
}
gameIsLive = true;
};
const handleCellClick = (e) => {
const classList = e.target.classList;
if (!gameIsLive || classList[1] === 'x' || classList[1] === 'o') {
return;
}
if (currentPlayer === 1) {
classList.add('playerOneColour');
} else {
classList.add('playerTwoColour');
}
if (xIsNext) {
classList.add("x");
} else {
classList.add('o');
}
checkGameStatus();
};
// event listeners
resetDiv.addEventListener('click', handleReset);
for (const cellDiv of cellDivs) {
cellDiv.addEventListener('click', handleCellClick);
cellDiv.addEventListener('click', handleCellSelection);
}
//Matrix Builder
var counter = 0;
var matrix = [];
for (var i = 0; i < 3; i++) {
matrix[i] = [];
for (var j = 0; j < 3; j++) {
matrix[i][j] = [];
matrix[i][j] = counter;
++counter;
}
}
// 0,1,2,3,4,5,6,7,8
// 0,1,2,0,1,2,0,1,2
var playerCounter = 1;
var currentPlayer = 1;
function handleCellSelection(e) {
playerCounter++;
let htmlElement = e.target;
let cellType = htmlElement.getAttribute("data-cell");
let reuseNTI = numberToIndexes(cellType);
let matrixIndex = indexInMatrix(reuseNTI[0], reuseNTI[1]);
let isWinnerFunction = isPlayerWinner(matrix);
function indexInMatrix(index1, index2) {
if (currentPlayer === 2) {
return matrix[index1].splice([index2], 1, "X")
currentPlayer = 1;
} else {
return matrix[index1].splice([index2], 1, "O");
currentPlayer = 2;
}
}
function isPlayerWinner(matrix, currentPlayer) {
if (playerCounter < 6) {
return;
} else {
var xSign = "X";
var oSign = "O";
let rowX = 0;
let rowO = 0;
//TO DO CHECK COLUMN
for (var i = 0; i < matrix[0].length; i++) {
if (xSign === matrix[i][reuseNTI[0]]) {
rowX++
} else if (oSign === matrix[i][reuseNTI[0]]) {
rowO++
console.log(rowO)
}
// console.log(matrix[i, 0].lastIndexOf("X")) ; //000↓,111↓,222↓
// console.log(matrix[i, 0].lastIndexOf("O"));
}
//TO DO CHECK ROW
for (var i = 0; i < matrix[0].length; i++) {
if (xSign === matrix[reuseNTI[0][i]]) {
} else if (oSign === matrix[reuseNTI[0]][i]) {
}
// console.log(matrix[0, i].lastIndexOf("X")) ; //row is 000->,111->,222->
// console.log(matrix[0, i].lastIndexOf("O"));
}
//TO DO CHECK PRIMARY DIAGONAL
for (var i = 0; i < matrix[0].length; i++) {
if (xSign === matrix[i][i]) {
} else if (oSign === matrix[i][i]) {
}
// matrix[i][i];
// console.log(matrix[i, i].lastIndexOf("X")); //012->,012->,012->
// console.log(matrix[i, i].lastIndexOf("O"));
}
//TO DO CHECK SECONDARY DIAGONAL
for (var i = 0; i < matrix[0].length; i++) {
if (xSign === matrix[i][matrix.length - 1 - i]) {
} else if (oSign === matrix[i][matrix.length - 1 - i]) {
}
// matrix[i][matrix.length - 1 - i];
// console.log(matrix[i, matrix.length - 1 - i].lastIndexOf("X"));
// console.log(matrix[i, [matrix.length - 1 - i]].lastIndexOf("O"));
}
}
}
isPlayerWinner(matrix);
console.log(matrix);
}
function numberToIndexes(number) {
let row = Math.floor(number / 3);
let column = number % 3;
return [row, column];
}
var cellSize = 100;
var cellSpace = 10;
var matrixRows = matrix.length;
var matrixColumns = matrix[0].length;
for (var i = 0; i < matrixRows; i++) {
for (var j = 0; j < matrixColumns; j++) {
var cell = document.createElement("div");
cell.setAttribute("class", "cell");
matrixStage.appendChild(cell);
cell.style.top = i * (cellSize + cellSpace) + "px";
cell.style.left = j * (cellSize + cellSpace) + "px";
}
}
function newMatrixGrid() {
var grid3x3 = document.getElementById("matrixMaker").value;
if (grid3x3 == "3") {
var matrixStage = document.querySelector("#matrixStage").style.display = "block";
} else {
matrixStage = document.querySelector("#matrixStage").style.display = "none";
}
}
#player1{
color: blue;
}
#player2{
color: red;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
color: #545454;
display: grid;
font-family: sans-serif;
justify-content: center;
}
.container {
background: #ffffff;
margin: 50px;
padding: 50px;
border-radius: 25px;
}
.title {
text-align: center;
}
.title span {
color: #F2EBD3;
}
.status-action {
color:blue;
display: flex;
margin-top: 25px;
font-size: 25px;
justify-content: space-around;
height: 30px;
}
.status span {
color: red;
}
.reset {
color: black;
cursor: pointer;
}
.reset:hover {
color: #10976c;
}
.game-grid {
background: #000000;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
grid-gap: 15px;
margin-top: 50px;
}
.game-cell {
background:white;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
height: 200px;
width: 200px;
}
.playerOneColour{
filter: invert(9%) sepia(100%) saturate(7261%) hue-rotate(247deg) brightness(91%) contrast(146%);
}
.playerTwoColour{
filter: invert(14%) sepia(95%) saturate(6042%) hue-rotate(358deg) brightness(109%) contrast(117%);
}
.x {
color: transparent;
cursor: default;
}
.o {
color: transparent;
cursor: default;
}
.x::after {
background-image: url(../Resources/X.png);
background-size:contain;
background-repeat: no-repeat;
margin-top: 80px;
content: '×';
}
.o::after {
background-image: url(../Resources/O.png);
background-size:contain;
background-repeat: no-repeat;
margin-top: 100px;
content: '○';
}
.won::after {
filter: invert(100%) sepia() saturate(10000%) hue-rotate(0deg);
}
#media only screen and (min-width: 1024px) {
.game-grid {
margin-top: 25px;
grid-gap: 10px;
}
.game-cell {
height: 150px;
width: 150px;
}
.x::after {
font-size: 150px;
}
.o::after {
font-size: 175px;
}
}
#media only screen and (max-width: 540px) {
.container {
margin: 25px;
padding: 25px;
}
.game-cell {
height: 100px;
width: 100px;
}
.x::after {
font-size: 100px;
}
.o::after {
font-size: 125px;
}
}
#matrixStage{
position:relative;
}
.cell
{
position: absolute;
width: 100px;
height: 100px;
border: 1px solid black;
background-color: white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Play XO</title>
<link rel="StyleSheet" href="Styles/index.css">
</head>
<body>
<form id="formInput">
<h1>Play X O </h1><br>
<label for="player1" id="player1">Player 1:</label><br>
<input type="text" id="player1Input"><br>
<label for="player1" id="player2">Player 2:</label><br>
<input type="text" id="player2Input"><br><br>
<button type="button" onclick="getInputValue();"> Start Game</button>
</form>
<br>
</form>
<div class="container" style="display:none" id="container">
<h1 class="title">Play X O </h1>
<div class="status-action">
<div class="status">Player 1 turn</div>
<div class="reset">Reset</div>
</div>
<div class="game-grid">
<div class="game-cell" data-cell="0"></div>
<div class="game-cell" data-cell="1"></div>
<div class="game-cell" data-cell="2"></div>
<div class="game-cell" data-cell="3"></div>
<div class="game-cell" data-cell="4"></div>
<div class="game-cell" data-cell="5"></div>
<div class="game-cell" data-cell="6"></div>
<div class="game-cell" data-cell="7"></div>
<div class="game-cell" data-cell="8"></div>
</div>
</div>
<select name="matrix-size" id="matrixMaker" onchange="newMatrixGrid()">
<option value="3">3X3</option>
<option value="4">4X4</option>
<option value="5">5X5</option>
</select>
</br></br></br>
<div id="matrixStage"></div>
<script src="Scripts/index.js"></script>
</body>
</html>
I think you can simplify your isPlayerWinner function by ignoring if you are looking for Xs or Os. You must assume the last token used was not the winner in the previous turn or the game would already be finished.
So if you have matrix = [[0,1,2],[3,4,5],[6,7,8]] and the numbers will be progressively replaced by x or o just check if all items in a combination are equal
function isPlayerWinner(){
for(let i=0; i<3; i++){
const row = matrix[i][0] === matrix[i][1] && matrix[i][1] === matrix[i][2];
const column = matrix[0][i] === matrix[1][i] && matrix[1][i] === matrix[2][i];
if(column || row){
return true
}
}
if(matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2]){
return true;
}
if(matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0]){
return true;
}
return false
}
I have two text input id: input1 and input2. I would like to simulate keypress on input1 to input2. I cannot copy values onblur because after simulation I shall change the value of input1. Could you please let me know how to do this in jQuery 1.6 or Javascript? I tried below, but this isn't working and changing the value i.e. $('#'+origid).val() returns blank.
$(".maskedinput").keyup(function (e) {
var value = $.trim($(this).val());
var origid = $(this).attr('origid');
var originalelemevt = jQuery.Event( "keypress" );
originalelemevt.which = e.which;
originalelemevt.keycode = e.keycode;
$('#'+origid).trigger( originalelemevt );
var newval = '';
if(value.length >=4){
var orignal = value.substring(0,value.length-4);
for(var i=0;i<orignal.length;i++)
newval +='*';
newval +=value.substring(orignal.length);
$(this).val(newval);
}
});
$(document).ready(function() {
$("#I1").keyup(function (e) {
var value = $.trim($(this).val());
var newval = '';
if(value.length >=4){
var orignal = value.substring(0,value.length-4);
for(var i=0;i<orignal.length;i++)
newval +='*';
newval +=value.substring(orignal.length);
$(this).val(newval);
}
$('#I2').val(e.target.value);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<form id='F1'>
<input id='I1'>
<input id='I2'>
</form>
This what I was looking for, keypress event on id1.
$("#id1").keypress(function(e) {
var inputkey = e.which || e.keyCode;
var result = getInputSelection(document.getElementById("id1"));
$("#id2").trigger("keypress")
.val(function(i, val) {
var key = e.which || e.keyCode;
// return this.value + String.fromCharCode(key);
return this.value.substr(0, result.start) + String.fromCharCode(key) + this.value.substr(result.end)
});
});
$("#id1").keyup(function(e) {
mask('id1');
});
$("#id1").keydown(function(e) {
var inputkey = e.which || e.keyCode;
//alert(inputkey);
if (inputkey == 8) {
e.preventDefault();
var new_val = replaceValue(inputkey);
//alert(new_val);
$("#id1").val(new_val);
$("#id2").val(new_val);
// mask('id1');
} else if (inputkey == 46) {
e.preventDefault();
var new_val = replaceValue(inputkey);
//alert(new_val);
$("#id1").val(new_val);
$("#id2").val(new_val);
// mask('id1');
}
});
function mask(elid) {
var $this = $('#' + elid);
$this.val($this.val().replace(/.(?=.{4})/g, '*'));
}
function replaceValue(inputkey) {
var result = getInputSelection(document.getElementById("id1"));
// alert("Backspace "+result.start +","+result.end);
var new_val = $("#id1").val();
if (result.start == result.end) {
if (inputkey == 8) {
new_val = $("#id2").val().substr(0, result.start - 1) + $("#id2").val().substr(result.end);
} else if (inputkey == 46) {
new_val = $("#id2").val().substr(0, result.start) + $("#id2").val().substr(result.end + 1);
}
} else {
new_val = $("#id2").val().substr(0, result.start) + $("#id2").val().substr(result.end);
}
return new_val;
}
function getInputSelection(el) {
var start = 0,
end = 0,
normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#banner-message {
background: #fff;
border-radius: 4px;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
#banner-message.alt {
background: #0084ff;
color: #fff;
margin-top: 40px;
width: 200px;
}
#banner-message.alt button {
background: #fff;
color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="banner-message">
SSN:
<input type="text" id="id1" />
<input type="text" id="id2" style="display:none" />
</div>