2022 Web Development Bootcamp

Section 14: Milestone Project: Tic Tac Toe - Using Our JavaScript ( & HTML & CSS) Knowledge

olivia_yj 2022. 8. 30. 03:16

The goals

💪🏻Practice and apply what we learned

✌🏻Handling form submission with Javascript & creating objects with the "new" keyword

👍🏻Managing data with JavaScript, HTML and the "data-" attributes

 

Page / Project Features

Configure player names

Form with input field in modal overlay; also validate user input and show validation feedback

 

(Re-)Start Game

"Start Game" button should clear current game board or "Game Over" messsage

 

Turn-based Gameplay

Turns should switch automatically between the two players, every player has his / her own symbol

 

Select Fields & Check for Winner

Game fields are clickable & the player's symbol is displayed; Check for winner (regualr Tic-Tac-Toe rules) after every turn

 

Show "Game Over" Window

Present "Game Over" message which highlights winner (or draw) once the game ends

 

Let's try!

Event.preventDefault()

The preventDefault() method of the Event interface tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be.

The event continues to propagate as usual, unless one of its event listeners calls stopPropagation() or stopImmediatePropagation(), either of which terminates propagation at once.

As noted below, calling preventDefault() for a non-cancelable event, such as one dispatched via EventTarget.dispatchEvent(), without specifying cancelable: true has no effect.

FormData()

The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the fetch() or XMLHttpRequest.send() method. It uses the same format a form would use if the encoding type were set to "multipart/form-data".

You can also pass it directly to the URLSearchParams constructor if you want to generate query parameters in the way a <form> would do if it were using simple GET submission.

An object implementing FormData can directly be used in a for...of structure, instead of entries(): for (const p of myFormData) is equivalent to for (const p of myFormData.entries()).

 

Web APIs

Web API as the name suggests, is an API over the web which can be accessed using HTTP protocol. It is a concept and not a technology. We can build Web API using different technologies such as Java, .NET etc. For example, Twitter's REST APIs provide programmatic access to read and write data using which we can integrate twitter's capabilities into our own application.

When writing code for the Web, there are a large number of Web APIs available. Web APIs are typically used with JavaScript, although this doesn't always have to be the case.

 

object.trim()

The trim() method removes whitespace from both ends of a string and returns a new string, without modifying the original string. Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.) and all the line terminator characters (LF, CR, etc.).

 

.classList

The Element.classList is a read-only property that returns a live DOMTokenList collection of the class attributes of the element. This can then be used to manipulate the class list.

Using classList is a convenient alternative to accessing an element's list of classes as a space-delimited string via element.className.

 

.classList and className

Using "classList", we can add or remove a class without affecting any others the element may have. But if we assign "className", it will wipe out any existing classes while adding the new one (or if we assign an empty string it will wipe out all of them).

Assigning "className" can be a convenience for cases where we are certain no other classes will be used on the element, but it normally uses the "classList" methods exclusively.

And "classList" also has handy "toggle" and "replace" methods.

 

data attribute and dataset

The dataset read-only property of the HTML Element interface provides read/write access to custom data attributes (data-*) on elements. It exposes a map of strings (DOMStringMap) with an entry for each data-* attribute.

Note: The dataset property itself can be read, but not directly written. Instead, all writes must be to the individual properties within the dataset, which in turn represent the data attributes.

 

Name conversion

dash-style to camelCase conversion

A custom data attribute name is transformed to a key for the DOMStringMap entry by the following:

  1. Lowercase all ASCII capital letters (A to Z);
  2. Remove the prefix data- (including the dash);
  3. For any dash (U+002D) followed by an ASCII lowercase letter a to z, remove the dash and uppercase the letter;
  4. Other characters (including other dashes) are left unchanged.
camelCase to dash-style conversion

The opposite transformation, which maps a key to an attribute name, uses the following:

  1. Restriction: Before transformation, a dash must not be immediately followed by an ASCII lowercase letter a to z;
  2. Add the data- prefix;
  3. Add a dash before any ASCII uppercase letter A to Z, then lowercase the letter;
  4. Other characters are left unchanged.

For example, a data-abc-def attribute corresponds to dataset.abcDef.

Accessing values

  • Attributes can be set and read by the camelCase name/key as an object property of the dataset: element.dataset.keyname.
  • Attributes can also be set and read using bracket syntax: element.dataset['keyname'].
  • The in operator can check if a given attribute exists: 'keyname' in element.dataset.

Setting values

  • When the attribute is set, its value is always converted to a string. For example: element.dataset.example = null is converted into data-example="null".
  • To remove an attribute, you can use the delete operator: delete element.dataset.keyname.
<div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>John Doe</div>
const el = document.querySelector('#user');

// el.id === 'user'
// el.dataset.id === '1234567890'
// el.dataset.user === 'johndoe'
// el.dataset.dateOfBirth === ''

// set a data attribute
el.dataset.dateOfBirth = '1960-10-03';
// Result on JS: el.dataset.dateOfBirth === '1960-10-03'
// Result on HTML: <div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth="1960-10-03">John Doe</div>

delete el.dataset.dateOfBirth;
// Result on JS: el.dataset.dateOfBirth === undefined
// Result on HTML: <div id="user" data-id="1234567890" data-user="johndoe">John Doe</div>

if (!('someDataAttr' in el.dataset)) {
  el.dataset.someDataAttr = 'mydata';
  // Result on JS: 'someDataAttr' in el.dataset === true
  // Result on HTML: <div id="user" data-id="1234567890" data-user="johndoe" data-some-data-attr="mydata">John Doe</div>
}

DOM traversal

One of the most important skills of a web developer is DOM traversal and being able to select HTML elements with JavaScript. 

 

  • The entire document is a document node
  • Every HTML element is an element node
  • The text inside HTML elements are text nodes
  • All comments are comment nodes

  • parentNode
  • previousSibling
  • nextSibling
  • firstChild
  • lastChild
  • childNodes[nodeNumber]
 

effect of "return"in  if-statement 

When a return statement is used in a function body, the execution of the function is stopped. If specified, a given value is returned to the function caller. For example, the following function returns the square of its argument, x, where x is a number.

Interrupt a function

A function immediately stops at the point where return is called.

 

 

 

Self Training💪🏻

1. Build HTML

Answer

<body>
    <div id="backdrop"></div>
    <header id="main-header">
      <h1>Play Tic, Tac, Toe</h1>
      <p>Built with HTML, CSS, JavaScript and - of course - lots of love!</p>
    </header>
    <main>
      <aside class="modal" id="config-overlay">
        <h2>Choose your name</h2>

        <form>
          <div class="form-control">
            <label for="playername">Player name</label>
            <input type="text" name="playername" id="playername" required />
          </div>
          <p id="config-errors"></p>
          <div>
            <button type="reset" class="btn btn-alt" id="cancel-config-btn">
              Cancel
            </button>
            <button type="submit" class="btn">Confirm</button>
          </div>
        </form>
      </aside>
      <section id="game-configuration">
        <ol>
          <li>
            <article id="player-1-data">
              <h2>Player 1</h2>
              <h3>PLAYER NAME</h3>
              <p class="player-symbol">X</p>
              <button
                class="btn btn-alt"
                id="edit-player-1-btn"
                data-playerid="1"
              >
                Edit
              </button>
            </article>
          </li>
          <li>
            <article id="player-2-data">
              <h2>Player 2</h2>
              <h3>PLAYER NAME</h3>
              <p class="player-symbol">O</p>
              <button
                class="btn btn-alt"
                id="edit-player-2-btn"
                data-playerid="2"
              >
                Edit
              </button>
            </article>
          </li>
        </ol>
        <button class="btn" id="start-game-btn">Start New Game</button>
      </section>

      <section id="active-game">
        <article id="game-over">
          <h2>You won, <span id="winner-name">PLAYER NAME</span>!</h2>
          <p>Click "Start New Game" above, to start a new game!</p>
        </article>

        <p>It's your turn <span id="active-player-name">PLAYER NAME</span>!</p>
        <ol id="game-board">
          <li data-col="1" data-row="1"></li>
          <li data-col="2" data-row="1"></li>
          <li data-col="3" data-row="1"></li>

          <li data-col="1" data-row="2"></li>
          <li data-col="2" data-row="2"></li>
          <li data-col="3" data-row="2"></li>

          <li data-col="1" data-row="3"></li>
          <li data-col="2" data-row="3"></li>
          <li data-col="3" data-row="3"></li>
        </ol>
      </section>
    </main>
  </body>

 

Mine

<body>
  <header>
    <h1>Play Tic, Tac, Toe</h1>
    <p>Built with HTML, CSS, JavaScript and - of course - lots of love!</p>
  </header>
  <main>
    <aside id="config-player">
      <h2>Choose your name</h2>
      <p>Player name</p>
      <input type="text" id="playername-set" />
      <button>Cancel</button>
      <button>Confirm</button>
    </aside>
    <div class="player-card">
      <section>
        <div>
          <p>Player 1</p>
          <h2 id="player-1">PLAYER NAME</h2>
          <p class="player-symbol">X</p>
          <a href="#config-player">Edit</a>
        </div>
      </section>
      <section>
        <div>
          <p>Player 2</p>
          <h2>PLAYER NAME</h2>
          <p class="player-symbol">O</p>
          <a href="#config-player">Edit</a>
        </div>
      </section>
    </div>
    <button id="start-new-game" type="reset">Start New Game</button>
  </main>  
  <footer>

  </footer>
</body>

👀Differences

1. An instructor used form inside aside which I didn't use

2. He used ol, li and put article inside. But I used section and div

 

2. Use CSS

👀Differences

1. colors are different obviously....at least found some similar colors tho!

2. I think I suck at positioning....

3. Need to control some margin and padding

 

Answer

body {
  margin: 0;
  font-family: 'Open-Sans', sans-serif;
  color: rgb(44, 41, 44);
  background-color: rgb(247, 239, 247);
}

#main-header {
  background-color: rgb(140, 0, 255);
  color: white;
  padding: 2rem 5%;
  text-align: center;
}

.btn {
  font: inherit;
  padding: 0.5rem 1.5rem;
  background-color: rgb(140, 0, 255);
  border: 1px solid rgb(140, 0, 255);
  color: white;
  border-radius: 4px;
  cursor: pointer;
}

.btn-alt {
  background-color: transparent;
  border-color: transparent;
  color: rgb(140, 0, 255);
}

.btn:hover {
  background-color: rgb(79, 10, 190);
  border-color: rgb(79, 10, 190);
}

.btn-alt:hover {
  background-color: rgb(230, 201, 252);
  border-color: transparent;
}

Mine

body {
  font-family: 'Open-Sans', sans-serif;
  background-color: rgb(249, 242, 255);
  margin: 0;
  height: 100%;
  width: 100%;
}

header {
  width: 100%;
  height: 10rem;
  margin: 0;
  padding: 0;
  background-color: rgb(143, 51, 255);
  color: white;
  text-align: center;
}

main {
  text-align: center;
}

header h1 {
  margin: 0;
  padding: 2rem 5% 0;
}

.player-card {
  display: flex;
  text-align: center;
  justify-content: space-around;
  margin: 0 25%;
}

section {
  width: 90%;
  background-color: rgb(243, 228, 255);
  margin: 4rem 1rem;
  border-radius: 3px;
  box-shadow: 2px 2px rgba(177, 177, 177, 0.421);
}

section div {
  margin: 0;
  padding: 1rem 0rem;
}

section p {
  font-weight: bold;
  margin: 8px auto;
}

section h2 {
  color: rgb(91, 26, 152);
  margin: 8px 0;
}

section .player-symbol {
  font-size: 30px;
}

section a {
  text-decoration: none;
  color: blueviolet;
}

#start-new-game {
  width: 12rem;
  height: 2rem;
  font-size: 16px;
  margin: 0;
  border: none;
  border-radius: 3px;
  background-color: blueviolet;
  color: white;
  margin: 0 2rem;
}

😭😭😭😭😭😭😭

Since I am just a beginner I used too many code lines...and it looks messy....let me fix it step by step...🥺

and he separated some parts of website into different css file...

 

 

What I need to prepare more

1. how to put body items in the middle

-not only width 50%

=> it was 'text-align'

2. what is 'width: 90%' for?

3. how to use media query

 

 

 

Sources

https://developer.mozilla.org/en-US/docs/Web/API

 

Web APIs | MDN

When writing code for the Web, there are a large number of Web APIs available. Below is a list of all the APIs and interfaces (object types) that you may be able to use while developing your Web app or site.

developer.mozilla.org

https://developer.mozilla.org/en-US/docs/Web/API/FormData

 

FormData - Web APIs | MDN

The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the fetch() or XMLHttpRequest.send() method. It uses the same format a form would use if the e

developer.mozilla.org

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim

 

String.prototype.trim() - JavaScript | MDN

The trim() method removes whitespace from both ends of a string and returns a new string, without modifying the original string. Whitespace in this context is all the whitespace characters (space, tab, no-break space, etc.) and all the line terminator char

developer.mozilla.org

https://stackoverflow.com/questions/69361432/difference-between-classname-and-classlist#:~:text=Using%20%22classList%22%2C%20you%20can,wipe%20out%20all%20of%20them). 

 

Difference between className and classList

Which one of the following should be preferred under what circumstances? btnElement.classList.add('btn'); btnElement.className = 'btn';

stackoverflow.com

https://medium.com/codex/how-to-traverse-the-dom-in-javascript-7fece4a7751c

 

How To Traverse The DOM In JavaScript

Must know methods in DOM traversal

medium.com

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return#interrupt_a_function

 

return - JavaScript | MDN

The return statement ends function execution and specifies a value to be returned to the function caller.

developer.mozilla.org