- What is HTML?
- What is CSS?
- What is JavaScript?
All projects begin with creating single file! Create application entry point, which will be HTML document file
named index.html
- Base HTML document
- Create empty file
index.html
- Define document base structure
- define
!doctype
tag with attributehtml
on the first line - define
html
tag withhead
andbody
tags. Set lang attribute toen
- inside
head
tag- add
meta
tag with attributecharset
with valueutf-8
to set page encoding - add
title
tag with text childrenPlay Hangman!
- add
- define
- Inside
body
adddiv
tag with text childrenTest!
- Open file in a browser to see if it works. You should see text from
div
element and title of window in Tab should be as You defined intitle
tag
We need to separate code into files, according to its purpose. Connect style sheet and script file to your HTML document.
- loading stylesheets
- loading scripts
- printing to browser console
- Create empty file called
styles.css
- Add styling for
body
. You can create style rule with template below:[tagName or selector]: { [cssProperty]: value; }
- Set rule
family-font
with valuesans-serif
for tagbody
- Add styling for
- Link style sheet to HTML document. In
head
tag, inside document, add new taglink
with 3 attributesrel
attribute set linking relation, set value tostylesheet
type
attribute with valuetext/css
href
attribute with file name to link with valuestyles.css
- Open
index.html
in browser and inspectdiv
element to check if stylesheet is loaded.
- Create empty file
game.js
- inside add following line:
console.log('game script loaded');
- inside add following line:
- Link script to HTML document. Add
script
tag with 2 attributes as last child ofbody
tag:type
with valuetext/javascript
so browser can parse text as javascriptsrc
with valuegame.js
- Check browser console to see if message is printed
To make dynamic pages we need to manipulate DOM. We can edit, add or delete HTML elements.
- finding DOM element with
id
attribute - appending node to DOM
document
built-in functions- storing references using
const
- Inside
index.html
addid
attribute with valuegameContent
todiv
insidebody
to be able to find this element easily in javascript code - Inside
game.js
:- Using built-in function
document.getElementById
finddiv
with idgameContent
document.getElementById
function takes one parameter - element id- store returned value using
const
for later usage.
- Clear element content by changing element attribute
textConent
to empty string''
- To access element attribute use dot operator
gameContent.textContent
and attribute name. - To change attribute value, just assign new value directly as so:
element.attribute = newValue;
- To access element attribute use dot operator
- Check browser to see that text initially loaded with html file is cleared
- Create header element with text
Welcome to Hangman!
- To create element use
document.createElement
- Pass one argument to function with tagName with value
h1
- Set
textContent
attribute with valueWelcome to Hangman!
- store returned value using
const
with nameviewTitle
- Pass one argument to function with tagName with value
- Append created header element to previously stored found element
- To append children to element use method
appendChild
element.appendChild(childElement);
- To append children to element use method
- To create element use
- Check browser to see changes. Investigate Element tab in devTools to see html structure
- Using built-in function
Every web application is based on user events. Handle blur
event in input
element, to see what character user
is typing.
- listening for elements events
- inline functions
- Create
div
element with textEnter your name:
- store reference using
const
with namenameInputLabel
- store reference using
- Create
input
element- store reference using
const
with namenameInput
- store reference using
- Add event listener to
input
element- to add event listener to element use element method
addEventListener
- first argument of this method is event name, listen for an element blur event (fired when element loses focus) which value is
blur
- second argument is function which will be called every times element fires proper event
- inside event listener function add call to
console.log
and print value of event target- event listener function first argument is event object which describes an event that took place
- example:
nameInput.addEventListener('input', event => { console.log(event.target.value); });
- inside event listener function add call to
- first argument of this method is event name, listen for an element blur event (fired when element loses focus) which value is
- to add event listener to element use element method
- Append new elements to
div
with game content - Try entering some text and lose focus by a click outside input to see if console is printing text entered in input
Some values change over time. Use mutable let
to store some mutable data.
- mutable reference with
let
- Create variable for storing value from input with name
name
at file beginning- to store mutable value use
let
- while defining, assign empty string:
''
let
value can be reassigned whileconst
not
- to store mutable value use
- Inside input event listener assign value from an event to created variable
- After assigning print value of created variable, instead directly reading from event to check if value was stored correctly.
While writing code, it's getting longer and more complicated. Use function to group and encapsulate related logic.
- defining own functions with
function
keyword
- Create function called
welcomeView
, that takes no arguments- To create function use key word
function
followed by function name and then round parenthesis - example:
function nameIt() { // instructions }
- To create function use key word
- Move code to function (everything besides
let
for storing name,const
for storing reference to div with idgameContent
and clearing its content)- creating header, label and input
- event listening
- appending to DOM
- Call created function
- check browser, there should be no visible changes
Drawing to screen is repeatable process. We need to abstract rendering logic to function.
- conditions
if
statement
- Create mutable variable for storing active view name, with name
activeView
- initialize variable with value
welcome
- initialize variable with value
- Create function called
render
with no arguments - Move line with setting
gameContent.textContent
to empty string torender
function - Inside
render
check which view render- use
if
statement- example
if
statement:
if (condition1) { // do something }
- example
- if
activeView
is equal towelcome
callwelcomeView
- use
- Check browser if there is still no changes in application visually
Every modern application is capable of changing whole view in instant. Create abstraction for changing view.
- contacting strings
else if
- Create function
playView
- inside create
h1
element with text equal to'Hi, ' + name
- inside create
- Inside
welcomeView
function- Create
button
element with text equal toPlay game!
- Add event listener for event
click
- on every click change value of
activeView
toplay
- call
render
function
- on every click change value of
- append button to game content
- Create
- Add additional condition statement inside
render
usingelse if
, check ifactiveView
is equalplay
- call
playView
function
- call
- Check browser, test if clicking in the button with text
Play game!
changes view
Every game needs to be endless in terms of state. After ending game, we want to start over.
else
statement
- Create function
endGameView
with no arguments- create element
h1
with textGame finished!
- create
button
element with textPlay again
- add event listener for
click
event- change active view to welcome view
- call
render
- add event listener for
- append elements to game content
- create element
- Inside
playView
create button with textGive up
- listen for
click
event- change
activeView
value toendGame
- call
render
function
- change
- append element to game content
- listen for
- Append the button to game content
- Inside
render
function addelse
statement afterelse if
statement with call toendGameView
function
As game grows in logic, it stores more data, keeping it spread out all over code base is disaster. Define all game state as single object.
- objects
- Create an object named
gameState
- example:
const objectName = { key1: 'value', key2: 123, }
- Add field
name
with initial value''
- Add field
activeView
with initial valuewelcome
- Change all usage of
name
andactiveView
variables to usegameState
object - Delete unused variables
- Check browser to see if everything works
Create more elastic way of rendering view. Instead of modifying game content, view should return new content to be shown.
- Updating objects
- Create function
gameStateUpdate
with body below:function gameStateUpdate(newGameState) { Object.assign(gameState, newGameState); render(); }
- Add 3 arguments to all view functions
- first argument named
contnt
- second argument named
state
- third argument named
stateUpdate
- first argument named
- Pass
gameCotent
,gameState
andstateUpdate
to every view call - Change lines modifying
gameState
directly to calls withstateUpdate
with proper partial state updated- example:
stateUpdate({ activeView: 'play' });
- remove call to
render
- it's called by state update function now
- Change
gameState
usage inside views tostate
- Change
gameContent
usage inside views tocontent
- Set value for input while rendering welcome view with stored name
- access current input value with
value
field of element and assign new value from store
- access current input value with
- Inside render function
- add new mutable variable
viewContent
without initializer - inside
if
statement assign returned value toviewContent
- after
if
statement appendviewContent
to game content
- add new mutable variable
- Check browser to see that input won't change value - everything else should work as previously
Add some real game logic. Draw all alphabet letters in play view, store clicked letters and disable one that were already clicked.
- Arrays
for
loop
- At the beginning of file create variable to store all alphabet letters using array
- example array syntax
const array = ['element1', 'element2'];
- use english alphabet
- Add to
gameState
object new fieldselectedLetters
, and initialize it with empty array - Inside
playView
creatediv
element for storing letters buttons - Iterate over all letters and create
button
element- to iterate overall letters use
for
loop
for (let i = 0; i < 10; i++) { // iteration for 10 times }
- set button text to equal iterated letter
- set
disabled
attribute by checking instate.selectedLetters
includes iterated letter- use array method
includes
which takes one argument - element in an array you are looking for
- use array method
- add event listener for click event for every letter button
- on a click, update state so
state.selectedLetters
includes clicked letter- use array method
concat
- use array method
- on a click, update state so
- append the button to buttons container
- to iterate overall letters use
- Append buttons container to view content
We need so phrase to guess. Create some phrases and make some randomness logic while getting new phrase to guess.
- array function iterating
- logic operators
- randomness
- At the beginning of file create array for holding phrases that user will be guessing
- Create function for getting random phrase
- Inside create variable for holding random phrases array index
- Use
Math.floor
andMath.random
and phrases array length - return phrase at found index
- Use
- Inside create variable for holding random phrases array index
- Add a new field to game state called
secretPhrase
with initial value empty string - Inside
welcomeView
when user click button- update state so
secretPhrase
inside game state will be random phrase- use previously created function to get random phrase
- reset
selectedLetters
to empty array
- update state so
- Inside
playView
- Create a container for phrase letters (
div
) - Split
state.secretPhrase
into array holding single letter- use string method
string.split(seperator)
- split by empty string
''
- use string method
- Iterate over every letter
- use array function to iterate:
[1,2,3].forEach(number => { // iterates 3 times, every time argument `number` holding another element from iterated array })
- create span element
- check if letter is visible
- it is visible if letter is space character
- OR it is visible if letter is included in
state.selectedLetters
- use OR operator
||
- Set element text using previously calculated value (is letter visible) with ternary expression
- example ternary expression:
const result = condition ? ifConditionTrue : ifConditionFalse
- use asterisk character
*
for hidden letters
- Append a span to letters container
- Append letters container to view before letters buttons container
- Create a container for phrase letters (
We need to add some logic for game to end. Every time user sees all letters in a phrase - call it end game.
- string template
every
method on array
-
Inside play view add mutable variable for storing count of visible letters
- initialize it with number
0
- initialize it with number
-
Add to game state new field
mistakes
and initialize it with number0
-
Inside letter button listener
- check if clicked letter was mistake
- use string method
includes
- example
'abc'.includes('a'); // -> true
- use string method
- store check result in variable
- store selected letters to const (
const selectedLetters = state.selectedLetters.concat(letter);
)- inside
stateUpdate
use object short notation{ selectedLetters: selectedLetters}
is the same as{ selectedLetters }
- inside
- check if all letters are visible after selecting letter
- split
state.secretPhrase
with empty string to iterate over all letters usingevery
method- array method
every
return true, only if all iterations on array returns true - while iterating check if
selectedLetters
includes iterated letter- if iterated letter is space, return true
- store iteration result
- array method
- split
- update active view to
end
if all letters are visible or toplay
if not
- check if clicked letter was mistake
-
Increase mistakes count if letter button was mistake
- use ternary expression
- for a good click don't change value
-
In end view create
h3
element- use string template to interpolate a message for user, containing information about mistakes count
- example string template
const foo = 123; const text = `count: ${foo}`;
-
Clear
mistakes
andselectedLetters
for every time user clickPlay game!
button
Every time we refresh our page, progress is lost. Persist game state using browser local storage.
- localStorage
- JSON api
- Create variable for persisted game state read from local storage
- initialize it with loaded item from local storage
- example
const storedValue = localStorage.getItem('key');
- While initializing game state variable check if loaded game state from local storage is not empty and use this value
to initialize game state
- use ternary expression while assigning value
- parse value using JSON api
- use
parse
method from api to parse string into object
const parsedObject = JSON.parse('{ "a": true }'); // -> { a: true }
- use
- Update
gameStateUpdate
function, so it updates local storage on every state update- use
setItem
method from local storage api - parse game state object to string using JSON api
- use
stringify
method
const stringifiedObject = JSON.stringify({ a: true }); // -> '{ "a": true }'
- use
- use
Let draw Hangman! Every time, user make another mistake, draw another hangman part.
- template tag
- Add to
index.html
code below, afterdiv
with idgameContent
<template id="hangman"> <div class="hangmanContainer"> <div class="hangmanRow"> <div></div> <div class="hangmanHead"></div> <div></div> </div> <div class="hangmanRow"> <div class="hangmanLeftHand"></div> <div class="hangmanBody"></div> <div class="hangmanRightHand"></div> </div> <div class="hangmanRow"> <div class="hangmanLeftLeg"></div> <div></div> <div class="hangmanRightLeg"</div> </div> </div> </template>
- Add styles below to
styles.css
.hangmanContainer { width: 200px; display: flex; flex-direction: column; } .hangmanRow { display: flex; justify-content: center; } .hangmanHead { border: solid 5px; width: 25px; height: 25px; border-radius: 50%; opacity: 0; } .hangmanBody { border: solid 3px; height: 20px; opacity: 0; } .hangmanLeftHand { border: solid; transform: rotate(45deg); margin-right: 5px; opacity: 0; } .hangmanRightHand { border: solid; transform: rotate(-45deg); margin-left: 5px; opacity: 0; } .hangmanLeftLeg { border: solid; height: 30px; transform: rotate(25deg); margin-right: 5px; opacity: 0; } .hangmanRightLeg { border: solid; height: 30px; transform: rotate(-25deg); margin-left: 5px; opacity: 0; }
- Inside play view using
document.querySelector
findtemplate
element with idhangman
- store to variable
- Clone template using template element method
content.cloneNode
- pass
true
as argument
- pass
- Find element with class
hangmanHead
inside cloned element usingquerySelector
method- pass proper css selector as argument
- store it as variable
- Repeat process for
hangmanBody
,hangmanLeftHand
,hangmanRightHand
,hangmanLeftLeg
,hangmanRightLeg
- Set opacity style of every Hangman part
- change element style by changing
style
property- change
opacity
style property - check mistakes count and assign proper opacity value for every part
- if mistakes count is greater than
0
set head opacity to'1'
- for every mistake show one part more
- if mistakes count is greater than
- change
- change element style by changing
Keeping all code in one file is not a good idea. Extract view functions to separate files.
- global scope
- closures
- Create separate files for views functions
- Add scripts in
index.html
- add before
game.js
- add before
- Move code to files
After creating base project, You can try adding more functionalities by Your own, without steps with explanation.
- Game timer. Add a timer which will count down from fixed value 1a. Add way to set up time on first view
- Keyboard support. Try adding keyboard key pressed handling to update app state
- Score board. Add score board. It can be displayed on the last view, after game is over. Use player time, mistakes and phrase characters count to sort results.
- Load phreses from file using
fetch
api.
When your work is done, it is time to share it with world! Publish your project using GitHub pages
- Go push changes to github
- Go to project settings
- Scroll down to
GitHub Pages
section - Choose
master
branch as source - Done! Go to
username.gitbub.io/project-name
- Tag/TagName - html element name, for example
div
- Element/node - using proper tags You can create elements for example
<div>hello</div>
- Attribute or element attribute - element can have additional attributes, for example:
charset
is attribute ofmeta
tag -<meta charset="utf-8">
- Children of element/node are descent of this element, for example:
<div><p>hello</p></div>
, element with tagp
is children of element with tagdiv