How to Make Tetris in JavaScript: A Step-by-Step Guide
Introduction to Tetris and JavaScript
Tetris, the iconic puzzle game, has captured the hearts of millions worldwide since its creation in 1984. With its simple yet addictive gameplay, it remains a favorite among gamers of all ages. In this tutorial, we’ll explore how to create your own Tetris game using JavaScript, a popular programming language for web development. By the end of this guide, you’ll have a fully functional Tetris game that you can customize and share with others.
Setting Up the Development Environment
Before diving into the coding process, let’s ensure we have the necessary tools in place. To develop our Tetris game, we’ll need a text editor and a web browser. You can choose any text editor of your preference, such as Visual Studio Code, Sublime Text, or Atom. Additionally, ensure you have a modern web browser like Chrome or Firefox for testing and running the game.
Creating the Game Board and Tetriminos
To start building our Tetris game, we’ll first create the game board and the Tetriminos—the geometric shapes that fall down the board. We’ll utilize HTML5 canvas, a powerful element for drawing graphics on web pages. By using JavaScript, we can manipulate the canvas to render the game elements dynamically.
Implementing the Game Logic
Next, we’ll delve into implementing the game logic. This involves handling user input, moving the Tetriminos, and detecting collisions. JavaScript provides event listeners to capture user input, such as arrow key presses, which we’ll utilize to control the movement of the Tetriminos. By employing algorithms and data structures, we can manage the game’s mechanics, scoring, and level progression.
Styling and Enhancing the Game
Now that we have the core functionality of our Tetris game working, let’s focus on enhancing its appearance and user experience. With CSS, we can style the game elements, including the game board, Tetriminos, and background. You can unleash your creativity here by designing a visually appealing game interface. Additionally, consider adding sound effects or animations to make the game more engaging.
Conclusion and Next Steps
Congratulations! You’ve successfully created your own Tetris game using JavaScript. You’ve learned how to set up the development environment, build the game board and Tetriminos, implement the game logic, and enhance the game’s visual appeal. This tutorial serves as a starting point for further exploration and customization. You can experiment with different features, such as a high-score leaderboard, multiplayer functionality, or responsive design. Remember, the possibilities are endless when it comes to game development and JavaScript.
Keyword Clusters:
Cluster 1: Tetris, JavaScript, game development Cluster 2: HTML5 canvas, game elements, graphics Cluster 3: User input, movement, collisions, event listeners Cluster 4: Styling, CSS, game interface, visual appeal Cluster 5: Game logic, scoring, level progression, algorithms Cluster 6: Tetriminos, game board, mechanics, data structures Cluster 7: Sound effects, animations, user experience Cluster 8: Development environment, text editor, web browser
Index.html
Welcome to Tetris JS
welcome to
tetris js
secondary navigation buttons
Tetris.html
Tetris JS - Tetris
main game grid area
Score : 0
Lines : 0
Level : 0
instructions.html
Tetris JS -About Tetris
How to Tetris
A Brief History
Gameplay
Tetris is composed of a grid of play in which pieces of different geometric forms, called
"tetriminos", fall from the top of the grid.While falling, the player can move the pieces
laterally and rotate them until they touch the bottom of the grid or land on a piece that had been placed
before it. The objective of the game is to use the pieces to create as many horizontal lines of
blocks as possible. When a line is completed, it disappears, and the blocks placed above fall one rank.
Completing lines grants points, and accumulating a certain number of points moves the player up a level,
which increases the number of points granted per completed line.
Tetriminos
The pieces on which the game of Tetris is based around are called "tetriminos". Pajitnov's original version
for the Electronika 60 computer used green brackets to represent the blocks that make up tetriminos.
Versions of Tetris on the original Game Boy/Game Boy Color and on most dedicated handheld games use
monochrome or grayscale graphics, but most popular versions use a separate color for each distinct shape.
Prior to The Tetris Company's standardization in the early 2000s, those colors varied widely from
implementation to implementation.
Scoring
The scoring formula for the majority of Tetris products is built on the idea that more difficult line clears
should be awarded more points. For example, a single line clear in Tetris Zone is worth 100 points, clearing
four lines at once (known as a Tetris) is worth 800, while each subsequent back-to-back Tetris is worth
1,200. In conjunction, players can be awarded combos that exist in certain games which reward multiple
line clears in quick succession. The exact conditions for triggering combos, and the amount of importance
assigned to them, vary from game to game.
Nearly all Tetris games allow the player to press a button to increase the speed of the current piece's
descent or cause the piece to drop and lock into place immediately, known as a "soft drop" and a "hard
drop", respectively. While performing a soft drop, the player can also stop the piece's increased speed by
releasing the button before the piece settles into place. Some games only allow either soft drop or hard
drop; others have separate buttons for both. Many games award a number of points based on the height that
the piece fell before locking, so using the hard drop generally awards more points.
How to Play
You start a new game by pressing the Start Game button. Tetriminos will begin to fall from the top of the
grid and begin to pile up at the bottom. You, the player, must rotate the Tetriminos to best fit together
and complete lines across the width of the grid. Each successful clear will result in the line being removed
from the grid and you awarded 15 points. For every 5 lines cleared you will gain a level. The game continues
till the Tetriminos reach the top of the grid, at which point the game is over.
Controls
Left Arrow Key/ Left Button - Move Left
Right Arrow Key/ Right Button - Move Right
Up Arrow Key/ Rotate Button - Rotate 90 degees
Down Arrow Key/ Down - Move Down
Music can be Played or Paused by clicking the - Music off button
style.css
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Assistant:wght@300;400;500;600;700;800&family=Rammetto+One&display=swap');
* {
box-sizing: border-box;
margin: 0;
padding: 0;
border: none;
scroll-behavior: smooth;
}
/* navigation bar */
.navbar {
font-family: 'Assistant', sans-serif;
display: flex;
justify-content: space-between;
align-items: center;
background: url("images/blue-tetrimino.png");
background-repeat: no-repeat;
background-position: center;
background-size: cover;
color: white;
padding-right: 10px;
}
.brand-logo {
font-family: 'Rammetto One', sans-serif;
font-size: 1.25rem;
margin: 0;
padding: .55rem;
text-align: center;
color: #1f0322;
}
/* create an anchor on the brand logo that return the user back to home on click*/
.brand-logo a {
text-decoration: none;
color: #1f0322;
}
.navbar-links ul {
margin: 0;
padding: 0;
display: flex;
}
.navbar-links li {
list-style: none;
}
.navbar-links li a {
text-decoration: none;
color: #fff;
padding: 1rem;
display: block;
}
.navbar-links li:hover {
background: url('images/blue-tetrimino.png') no-repeat;
border-radius: 10px;
}
.navbar-links .active {
border: 2px solid white;
border-radius: 10px;
}
/* create a hamburger menu for mobile displays*/
.toggle-btn {
position: absolute;
top: 1.2rem;
right: 1rem;
display: none;
flex-direction: column;
justify-content: space-between;
width: 40px;
height: 30px;
}
.toggle-btn .line {
width: 100%;
height: 5px;
background-color: white;
border-radius: 10px;
}
/* media query to change the flow of the navbar on mobile devices*/
@media screen and (max-width: 400px) {
.toggle-btn {
display: flex;
}
.navbar-links {
display: none;
width: 100%;
}
.navbar {
flex-direction: column;
align-items: flex-start;
padding: 0;
}
.navbar-links ul {
flex-direction: column;
width: 100%;
}
.navbar-links li {
text-align: center;
}
.navbar-links li a {
padding: .5rem 1rem;
}
.navbar-links.active {
display: flex;
}
}
/* create background image for the landing page */
.main-bg {
background: url("images/orange-tetrimino.png");
height: 100vh;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
/* create background image for the instructions page */
.about-bg {
background: url("images/pink-tetrimino.jpg");
height: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
/* create background image for the scores page */
.scores-bg {
background: url("images/blue-tetrimino.png");
height: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
/* universal styling for the headings across all pages */
.title{
font-family: "Rammetto One", sans-serif;
margin: 20px auto;
text-align: center;
}
.title h1{
font-size: 2.5rem;
text-transform: uppercase;
color: #1f0322;
}
.title h2::after{
content: " ";
display: block;
height:2px;
width: 10rem;
margin: .25em auto;
background-color: blueviolet;
box-shadow: 0px 2px 8px 0px red;
}
.title p{
font-family: "Assistant", sans-serif;
font-size: 1.25rem;
margin: 0 auto;
padding: .5rem;
}
.heading{
font-weight: bold;
}
.links a{
font-family: "Assistant", sans-serif;
font-size: 1rem;
text-decoration: none;
margin-bottom: 1rem;
padding: .5rem;
text-align: center;
justify-content: center;
display: block;
}
/* game page panels */
.panels{
margin: 0 1rem;
width: 95%;
display:grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-gap:12px;
justify-content:center;
align-items:center;
}
/* main panel for the game grid and start button */
.box{
height:460px;
border: none;
box-shadow: 0 0.1rem 1.4rem 0 rgba(86, 185, 235, 0.5);
position:relative;
border-radius: 5px;
background-color:rgb(255, 127, 148);
}
/* create smaller side panels foe the buttons and game information */
.sidebox1{
height:320px;
}
.sidebox2{
height: 250px;
}
.box-content{
margin: 0;
position: absolute;
left: 50%;
top: 50%;
transform:translate(-50%, -50%);
}
.box-content h2{
color: #c24cf6;
visibility:hidden;
}
/* button used on the landing page and game screens */
.buttons{
text-align:center;
margin: 0 auto;
display:block;
}
/* styling for the buttons that so same for of action on the site */
.btn{
width: 20ch;
font-family: 'Assistant', sans-serif;
font-size: 1.12rem;
font-weight:bold;
background-color: #03011e;
border:2px solid #847655;
color: #fc6e22;
padding:1rem;
margin: .5rem auto;
border-radius: 10px;
justify-content: space-between;
transition: all 200ms ease-in-out;
text-decoration: none;
}
/* div to arrange the control buttons */
.controls{
text-align: center;
margin: 0 auto;
}
/* styling for the control keys left, rotate, right and down */
.control-btn{
max-width: 40ch;
font-family: 'Assistant', sans-serif;
font-size: 1.12rem;
font-weight: bold;
display: inline-block;
background-color: #03011e;
border:2px solid #847655;
color:#fc6e22;
padding:.5rem;
margin: .25rem 1rem;
border-radius: 10px;
transition: all 200ms ease-in-out;
text-decoration: none;
}
/* styling for the game information blocks */
.un-btn{
width: 20ch;
font-family: 'Assistant', sans-serif;
font-size: 1.12rem;
font-weight: bold;
background-color: #03011e;
border:2px solid #847655;
color: #fc6e22;
padding: 1rem;
margin:.5rem auto;
border-radius: 10px;
justify-content:space-between;
transition: all 200ms ease-in-out;
text-decoration: none;
}
.btn:hover{
background: #847655;
color: #fff;
cursor: pointer;
}
/* remove btn functionality during gameOver() and score form submissinon till requirements are met */
.btn[disabled]:hover{
cursor: not-allowed;
transform:none;
}
.control-btn:hover{
background: #847655;
color: #fff;
cursor: pointer;
}
.music{
padding:1rem;
margin:.5rem auto;
justify-content:space-between;
}
/* the grid created as the play area for housing the tetriminos */
.grid{
width: 200px;
height:400px;
border-radius: 5px;
background-color:lightgrey;
display:flex;
flex-wrap: wrap;
}
.grid div{
width:20px;
height:20px;
}
/* fallback color for tetrimino to display with the grid */
.tetrimino{
background-color:violet;
}
/* scores Page */
.high-score-wrapper{
margin: 0 auto;
padding:2rem;
}
.high-score{
text-align:center;
text-transform:uppercase;
}
.score{
text-align:center;
text-transform:uppercase;
}
/* styling for the score form */
form{
width:100%;
display:flex;
flex-direction:column;
align-items:center;
}
/* input for the player to enter their name */
input{
font-size: 1rem;
max-width: 20ch;
text-align: center;
margin-bottom: 1rem;
padding:1.5rem;
border:none;
box-shadow: 0 0.1rem 1.4rem 0 rgba(86, 185, 235, 0.5);
}
input::placeholder{
color:#ff1793;
}
/* footer section */
footer{
height:150px;
}
footer p{
font-family: 'Assistant', sans-serif;
font-size: .8rem;
padding:.25rem;
text-align: center;
}
.social-network{
text-align: center;
}
.social-network>li{
display:inline;
}
.social-network i{
font-size: 2.5rem;
margin: 1rem;
padding:.25rem;
color: #cea716;
justify-content:space-between;
}
/* an arrow fixed to scroll with the screen, so that a user can quickly return to the top of the page */
.arrow-top{
position:fixed;
right: .5rem;
bottom:.25rem;
font-family: 'Rammetto One', sans-serif;
font-size: 2rem;
color: #cea716;
}
main.js
document.addEventListener('DOMContentLoaded', () => {
const toggle = document.getElementsByClassName('toggle-btn')[0];
const navbar = document.getElementsByClassName('navbar-links')[0];
const grid = document.querySelector('.grid');
let blox = Array.from(document.querySelectorAll('.grid div'));
const width = 10;
console.log(blox); //checking to make sure the array is correct
const startButton = document.getElementById('start-button');
let timerId;
const playerScore = document.getElementById('score');
let score = 0;
const gameLine = document.getElementById('lines');
let lines = 0;
const playerLevel = document.getElementById('levels');
let level = 0;
const gameMusic = document.getElementById('music');
const soundButton = document.getElementById('play');
let nextRandom = 0;
const colours = [
'MidnightBlue',
'Green',
'Orange',
'HotPink',
'DarkRed',
'Brown',
'Magenta'
];
// create a function that toggles the hamburger navigation menu
toggle.addEventListener('click', () => {
navbar.classList.toggle('active');
});
// create a function that toggles the music on or off using a button click
soundButton.addEventListener('click', () => {
if (gameMusic.muted == false) {
gameMusic.muted = true;
soundButton.innerHTML = 'Music Paused';
} else {
gameMusic.muted = false;
gameMusic.play();
gameMusic.volume = 0.3;
gameMusic.loop = true;
soundButton.innerHTML = 'Music Playing';
}
});
/**
* Create the arrays for each of the 7 Tetrimino shapes
* represented by q, p, s, z, t, b and i
*/
const pTetrimino = [
[2, 1, width + 1, width * 2 + 1],
[width, width + 1, width + 2, width * 2 + 2],
[width * 2, width * 2 + 1, width + 1, 1],
[0, width, width + 1, width + 2]
];
const qTetrimino = [
[0, 1, width + 1, width * 2 + 1],
[width, width + 1, width + 2, 2],
[width * 2 + 2, width * 2 + 1, width + 1, 1],
[width * 2, width, width + 1, width + 2]
];
const sTetrimino = [
[width * 2, width * 2 + 1, width + 1, width + 2],
[0, width, width + 1, width * 2 + 1],
[2, 1, width + 1, width],
[width * 2 + 2, width + 2, width + 1, 1]
];
const zTetrimino = [
[width, width + 1, width * 2 + 1, width * 2 + 2],
[1, width + 1, width, width * 2],
[0, 1, width + 1, width + 2],
[width * 2 + 1, width + 1, width + 2, 2]
];
const tTetrimino = [
[1, width, width + 1, width + 2],
[width + 2, 1, width + 1, width * 2 + 1],
[width * 2 + 1, width, width + 1, width + 2],
[width, 1, width + 1, width * 2 + 1]
];
//square tetrimino - called b for block
const bTetrimino = [
[0, 1, width, width + 1],
[1, 2, width + 1, width + 2],
[width + 1, width + 2, width * 2 + 1, width * 2 + 2],
[width, width + 1, width * 2, width * 2 + 1]
];
const iTetrimino = [
[1, width + 1, width * 2 + 1, width * 3 + 1],
[width, width + 1, width + 2, width + 3],
[2, width + 2, width * 2 + 2, width * 3 + 2],
[width * 2, width * 2 + 1, width * 2 + 2, width * 2 + 3]
];
const theTetriminos = [pTetrimino, qTetrimino, sTetrimino, zTetrimino, tTetrimino, bTetrimino, iTetrimino];
console.log(theTetriminos[0][0]); // checking to ensure the tetriminos are output correctly
//create an start position and rotation for the tetrimino
let currentPosition = 4;
let currentRotation = 0;
console.log(currentPosition, currentRotation);
//create a random tetrimino and its rotation
let random = Math.floor(Math.random() * theTetriminos.length);
let current = theTetriminos[random][currentRotation];
console.log(current); //checking output of current, testing random and currentRotation
//add the tetrimino to the grid with a draw function
function draw() {
current.forEach(index => {
blox[currentPosition + index].classList.add('tetrimino');
blox[currentPosition + index].style.backgroundColor = colours[random];
});
}
//console.log(draw()); //testing to see if a random tetrimino appears on the grid
//remove the tetrimino from the grid with an undraw function
function undraw() {
current.forEach(index => {
blox[currentPosition + index].classList.remove('tetrimino');
blox[currentPosition + index].style.backgroundColor = '';
});
}
// start button acts as start/pause game button
startButton.addEventListener('click', () => {
if (timerId) {
clearInterval(timerId);
timerId = null;
startButton.innerHTML = 'Game Paused'; //change text to show gameplay is paused
} else {
draw();
timerId = setInterval(moveDown, 1000);
startButton.innerHTML = 'Started'; //change text to show gameplay is running
nextRandom = Math.floor(Math.random() * theTetriminos.length);
}
});
//create a function to move the tetriminos down the grid
function moveDown() {
undraw();
currentPosition += width;
draw();
freeze();
}
//create a function that freezes the tetrimino when it hits the bottom of the div
function freeze() {
if (current.some(index => blox[currentPosition + index + width].classList.contains('taken'))) {
current.forEach(index => blox[currentPosition + index].classList.add('taken'));
//introduce a new tetrimino to the grid
random = nextRandom;
nextRandom = Math.floor(Math.random() * theTetriminos.length);
current = theTetriminos[random][currentRotation];
currentPosition = 4;
draw();
addScore();
gameOver();
}
}
//create a function to move the tetrimino to the left until it reaches the edge of the grid
function moveLeft() {
undraw();
const leftEdge = current.some(index => (currentPosition + index) % width === 0); //check to make sure the tetrimino does not exceed the left edge
if (!leftEdge) currentPosition -= 1;
if (current.some(index => blox[currentPosition + index].classList.contains('taken'))) {
currentPosition += 1;
}
draw();
}
//create a function to bind directional movement to the arrow keys on the keyboard
function control(event) {
event.preventDefault(); // prevents default screen movement when pressing the arrow keys
if (event.keyCode === 37) {
moveLeft();
} else if (event.keyCode === 39) {
moveRight();
} else if (event.keyCode === 40) {
moveDown();
} else if (event.keyCode === 38) {
turnShape();
}
}
//create an event listener to listen for keypresses and invoke the control functions
document.addEventListener('keydown', control);
//create event listener to listen for mouse clicks and invoke the control functions
const leftButton = document.getElementById('left');
const rotateButton = document.getElementById('rotate');
const rightButton = document.getElementById('right');
const downButton = document.getElementById('down');
leftButton.addEventListener('click', () => {
moveLeft();
});
rotateButton.addEventListener('click', () => {
turnShape();
});
rightButton.addEventListener('click', () => {
moveRight();
});
downButton.addEventListener('click', () => {
moveDown();
});
//create a function to move the tetrimino to the right until it reaches the edge of the grid
function moveRight() {
undraw();
const rightEdge = current.some(index => (currentPosition + index) % width === width - 1); //check to make sure the tetrimino does not exceed the right edge
if (!rightEdge) currentPosition += 1;
if (current.some(index => blox[currentPosition + index].classList.contains('taken'))) {
currentPosition -= 1;
}
draw();
}
//create a function to turn the tetrimino around by a 90 degree rotation
function turnShape() {
undraw(); //undraw the current tetrimino
currentRotation++; //increment the rotation by 1 turn
if (currentRotation === current.length) {
currentRotation = 0; //set new rotation
}
current = theTetriminos[random][currentRotation];
draw(); //draw the new rotation
}
/* limited coding experience resulted in this bugged code.
* I tried coding a display grid to show the upNext tetrimino for the player, but failed to get it to display
* correctly. Due to limited knowledge and experience with JS, I opted to comment this
* block of code out and return to it at a later date, as a future update, when I have
* the sufficient skill level
* ***************************************************************************************************************
//create a next up display grid so the player knows which tetrimino is falling next
const nextBlox = document.querySelectorAll('.display-grid div');
const nextWidth = 4; // define the size of the display grid
let nextIndex = 0;
console.log(nextBlox); //check that the display grid is correct
//create the first position of the tetrimino in the display grid so the player can see whats up next
const nextTetrimino = [
[2, 1, nextWidth + 1, nextWidth * 2 + 1], //pTetrimino
[0, 1, nextWidth + 1, nextWidth * 2 + 1], //qTetrimino
[nextWidth * 2, nextWidth * 2 + 1, nextWidth + 1, nextWidth + 2], //sTetrimino
[nextWidth, nextWidth + 1, nextWidth * 2 + 1, nextWidth * 2 + 2], //zTetrimino
[1, nextWidth, nextWidth + 1, nextWidth + 2], //tTetrimino
[0, 1, nextWidth, nextWidth + 1], //bTetrimino
[1, nextWidth + 1, nextWidth * 2 + 1, nextWidth * 3 + 1] //iTetrimino
];
//display next up tetrimino in the display grid
function nextUp() {
nextBlox.forEach( next => {
next.classList.remove('tetrimino');
});
nextTetrimino[nextRandom].forEach(index => {
nextBlox[nextIndex + index].classList.add('tetrimino');
});
}
*/
/** I tried a variety of methods to create a function whereby the players score
* would be taken from the gameOver() and passed to a finalScore that could be stored locally
*************************************************************************************************************/
//create a high score function to store the players highest scores locally
const playerName = document.getElementById('playerName');
const saveScoreBtn = document.getElementById('save-score');
const finalScore = document.getElementById('finalScore');
const mostRecentScore = localStorage.getItem('mostRecentScore');
const highScores = JSON.parse(localStorage.getItem('highScores')) || [];
finalScore.innerText = mostRecentScore;
playerName.addEventListener('keyup', () => {
saveScoreBtn.disabled = !playerName.value; //save button should be disabled until the player inputs their name
});
saveScore = (e) => {
e.preventDefault();
const score = {
score: mostRecentScore,
name: playerName.value,
};
highScores.push(score);
highScores.sort((a, b) => b.score - a.score);
highScores.splice(3);
localStorage.setItem('highScores', JSON.stringify(highScores)); //stores the players score in the localStorage
window.location.assign( ' / ');
};
//create function to add score to game for clearing lines
function addScore() {
for (let i = 0; i < 199; i += width) { // for loop to iterate through the entire grid
const row = [i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9];
if (row.every(index => blox[index].classList.contains('taken'))) {
score += 15; //increment the player score by 15 for every line cleared
playerScore.innerHTML = score;
lines += 1; //add 1 to the player dashboard to show the player how many lines they've cleared
gameLine.innerHTML = lines; {
if (lines % 4 === 0 && lines < 1001) { //increment the level for every 5 lines cleared
level += 1;
score += 100; //add 100 bonus points for every level gained
playerScore.innerHTML = score;
playerLevel.innerHTML = level;
}
}
row.forEach(index => {
blox[index].classList.remove('taken');
blox[index].classList.remove('tetrimino');
blox[index].style.backgroundColor = '';
});
const bloxRemoved = blox.splice(i, width);
blox = bloxRemoved.concat(blox);
blox.forEach(cell => grid.appendChild(cell));
}
}
}
//create a function to check the gameOver conditions
function gameOver() {
if (current.some(index => blox[currentPosition + index].classList.contains('taken'))) { // check to see if a taken shape is at the original index position
clearInterval(timerId); // stop the moveDown() function
startButton.innerHTML = 'Game Over';
startButton.style.backgroundColor = 'red';
startButton.style.color = 'white';
startButton.disabled = true; //disable the start button so that the game cannot continue
localStorage.setItem("mostRecentScore", score);
//redirect player to the scores page
return window.location.assign("index.html"); //player should be able to save score locally, navigate to other pages in the site
}
}
//create a function that validates the user input in the name field of scores.html
// TODO
function validateForm() {
let x = document.getElementById('PlayerName').value;
if (x == "" ) {
alert(' You must enter a name!');
return false;
}
}
validateForm();
});