Skip to main content

EVENT TARGETING

Lesson Objectives#

  1. Access the event parameter
  2. Use event.currentTarget to target the specific element being targeted
  3. Bonus: practice breaking a larger problem down into smaller steps

Getting started#

Create the following files and open the index.html in the browser

index.html
<!DOCTYPE html><html lang="en">  <head>    <meta charset="utf-8" />    <title></title>    <script      src="https://code.jquery.com/jquery-3.6.0.min.js"      charset="utf-8"    ></script>    <script src="app.js" charset="utf-8"></script>    <link rel="stylesheet" href="main.css" />  </head>  <body>    <div class="container">      <div class="card card-back">        <span class="top">&hearts;</span>        <h5 class="center">Q</h5>        <span class="bottom">&hearts;</span>      </div>      <div class="card card-back">        <span class="top">&hearts;</span>        <h5 class="center">K</h5>        <span class="bottom">&hearts;</span>      </div>      <div class="card card-back">        <span class="top">&hearts;</span>        <h5 class="center">K</h5>        <span class="bottom">&hearts;</span>      </div>      <div class="card-back card">        <span class="top">&hearts;</span>        <h5 class="center">Q</h5>        <span class="bottom">&hearts;</span>      </div>    </div>  </body></html>
app.js
console.log("Oh hey, I remember something like this");
main.css
/*********************************** GENEREAL***********************************/.container {  display: flex;  justify-content: space-around;}
h2 {  text-align: center;}
/*********************************** CARDS***********************************/.card {  flex-basis: 8em;  height: 12em;  border: 1px solid orange;  background: #FBFBFB;  box-shadow: 2px 2px 4px grey;  display: grid;  border-radius: 10%;  grid-template-columns: .5em 1.5em 4em 1.5em .5em;  grid-template-rows: 3em 5em 3em;  grid-column-gap: .5em;  grid-row-gap: .5em;  grid-template-areas:    ". . . top ."    ". . center . ."    ". bottom . . ."}
.top {  grid-area: top;}
.center {  grid-area: center;}
.bottom  {  grid-area: bottom;}.card h5 {  font-size: 5em;  margin: 0;  margin-top: -.3em;}
.card span {  color: hotpink;  font-size: 2em;}
.card-back span {  color: rgba(0,0,0,0);}
.card-back  {  /* adapted from: https://leaverou.github.io/css3patterns/#zig-zag */background:  linear-gradient(135deg, #FBFBFB 25%, transparent 25%) -50px 0,  linear-gradient(225deg, #FBFBFB 25%, transparent 25%) -50px 0,  linear-gradient(315deg, #FBFBFB 25%, transparent 25%),  linear-gradient(45deg, #FBFBFB 25%, transparent 25%);  background-size: 100px 100px;  background-color: mediumseagreen;  color: rgba(0,0,0,0);}
  • write a console.log to test that app.js is correctly connected

  • write your jQuery document on load function

  • select every div with a class of card

  • add an on click event handler that console logs something on click

Targeting our Target#

  • Let's get the card to 'flip over' by clicking on it. To do that we'll just toggle the 'card-back' class
$(() => {  const $card = $(".card").on("click", () => {    $(".card").toggleClass("card-back");  });});

Now when we click, we get all the cards to turn over.

What we need to do is target the very card we are clicking on. We can do this by accessing the event parameter

$(() => {  const $card = $(".card").on("click", (event) => {    console.log(event);    $(".card").toggleClass("card-back");  });});

Looks something like this:

We can go deeper and access the event.currentTarget

And, in this case, we see we clicked on the first card

We can covert it into a jQuery object by 'wrapping it in money'

    console.log($(event.currentTarget))

Great! Let's see if we can just toggle the class of this current target

$(() => {  const $card = $(".card").on("click", (event) => {    console.log($(event.currentTarget));    $(event.currentTarget).toggleClass("card-back");  });});

That's it! Now we can target each card and 'flip' it

Extra#

Let's check if the cards match. We may be tempted to do even more! What about removing matching cards? Flipping non-matching cards back over? Adding sound effects? Animations...

WHOA! Let's walk it back. We want to be sure that we are solving one small problem at a time. Trying to solve too many things at once is going to be one of your biggest challenges when you first start out.

Now that we have our cards flipping over - we just want to check if they match

  • we just have to solve this one problem
  • it's ok if it's not efficient or optimal
  • it's ok if you'll need to refactor your code for later steps
  • it's ok if it's buggy - you'll be able to click the same card twice and get a match - that's ok! At first you just want to solve one thing - imagine the perfect user who would never ever click the same card twice. Once you solve the simplest part, you can then work on fixing/preventing bugs

We need to store two cards. Let's make an array and a function to add the value of the card to the array if the array length is NOT 2

Let's set up a function:

const handOfCards = [];
$(() => {  const $card = $(".card").on("click", (event) => {    $(event.currentTarget).toggleClass("card-back");    playHand();  });});
const playHand = () => {  if (handOfCards.length === 2) {    console.log("checking", handOfCards);  } else {    console.log("adding to", handOfCards);    // need to push something to handOfCards  }};

Let's grab the value, let's console log one piece at a time

const playHand = () => {  if (handOfCards.length === 2) {    console.log("checking", handOfCards);  } else {    console.log("adding to", handOfCards);    // console.log($(event.currentTarget))    // console.log($(event.currentTarget).children())    // console.log($(event.currentTarget).children().eq(1))    // console.log($(event.currentTarget).children().eq(1).text())    handOfCards.push($(event.currentTarget).children().eq(1).text());  }};

We need to be able to call playHand when there are two cards in play

const playHand = () => {  if (handOfCards.length === 2) {    console.log("checking", handOfCards);  } else {    handOfCards.push($(event.currentTarget).children().eq(1).text());    // if after pushing the length is NOW 2    if (handOfCards.length === 2) {      playHand();    }  }};

Let's write some logic to do something if the cards match and else, if they don't match and in either case, let's empty the array

const checkHand = () => {  console.log("Ok I will check your cards", handOfCards);  if (handOfCards[0] === handOfCards[1]) {    $("body").append(`<h2>It's a match!</h2>`);  } else {    $("body").append(`<h2>It's NOT a match!</h2>`);  }  handOfCards = [];};

Uh oh handOfCards is set to a const variable, let's change it to let so we can clear the array after we are done checking two cards

const playHand = () => {  if (handOfCards.length === 2) {    checkHand();  } else {    handOfCards.push($(event.currentTarget).children().eq(1).text());    // if after pushing the length is NOW 2    if (handOfCards.length === 2) {      playHand();    }  }};

Potential Next Steps#

  • only add a value to the array if it is a card that is face down
  • if the cards don't match, have them flip back over
  • rather than append more and more h2s, replace the text
  • Upgrade the functionality to remove matching cards from the DOM
  • create a win state (no cards left - give a win message, reset the board)
  • create a lose state (too many turns used, give a lose message, reset the board)
  • Create the cards programmatically so they can be shuffled and placed in random order
  • Add more cards
  • Add a display of turns/plays/wrong guesses
  • Add an animation for card flipping