2

var cards = [
  {
    rank: "Queen",
    suit: "Hearts",
    cardImage: "images/queen-of-hearts.png",
    id: 0,
  },
  {
    rank: "Queen",
    suit: "Diamonds",
    cardImage: "images/queen-of-diamonds.png",
    id: 1,
  },
  {
    rank: "King",
    suit: "Hearts",
    cardImage: "images/king-of-hearts.png",
    id: 2,
  },
  {
    rank: "King",
    suit: "Diamonds",
    cardImage: "images/king-of-diamonds.png",
    id: 3
  }
];
//1
function createBoard() {
  for (var i = 0; i < cards.length; i++) {
    var cardElement = document.createElement('img');
    // console.log(cardElement);
    cardElement.setAttribute('src', 'images/back.png');
    cardElement.setAttribute('data-id', i);
    document.getElementById('game-board').appendChild(cardElement);
    cardElement.addEventListener('click', flipCard);
    cardElement.style.width = '210px';

  }
}
createBoard();
//2
function flipCard () {
  var cardId = this.getAttribute('data-id');
  cardsInPlay.push(cards[cardId].rank);
  cardsInPlay.push(cards[cardId].id);
  this.setAttribute('src', cards[cardId].cardImage);

// CHECK FOR MATCH HERE =>
    if (cardsInPlay.length === 2) {
      if (cardsInPlay[0] === cardsInPlay[1]) {
        alert("You found a match!");
      }
      else {
        alert("Sorry, try again.");
        console.log(cardsInPlay);
        cardsInPlay[0].setAttribute('src', 'images/back.png'); // this doesnt work
        cardsInPlay[1].setAttribute('src', 'images/back.png'); // this doesnt work
      }
    }
}
var cardsInPlay = [];
body{
    text-align: center;
    margin: 0;

}

h1 {
    font-family: "Raleway", sans-serif;
    font-weight: 400;
    color: #0d2c40;
    font-size: 45px;
    letter-spacing: 1px;
    margin: 0;
    color: white;
}

p {
  font-family: "Droid Serif", serif;
  line-height: 26px;
  font-size: 18px;
}

a {
    font-family: raleway;
    text-decoration: none;
    color: #F15B31;
    letter-spacing: 1px;
    font-weight: 600;
    font-size: 18px;

}

h2 {
    font-family: raleway;
    font-size: 20px;
    color: #0d2c40;
    letter-spacing: 1px;
    font-weight: 600;
}

header {
    background-color: #F15B31;
    padding: 30px 20px 30px 20px;
}

main {
  width: 850px;
  margin: 35px auto
}

a {
    margin: 0 20px;
    color: white;
}

nav a:hover {
    border-bottom: 2px solid white;
}

nav {
    background-color: #00A6B3;
    padding: 20px 0;
}

img {
    margin: 40px 8px 0 8px;
}

footer {
    text-transform: uppercase;
    padding: 0 20px;
    background-color: #0D2C40;
    color: white;
    letter-spacing: .08em;
    font-weight: 500;
}

.copyright {
    float: left;
}

.message {
    float: right;
}

.clearfix:after {
  visibility: hidden;
  display: block;
  content: " ";
  clear: both;
  height: 0;
  font-size: 0;
}

.name {
   color: #F15B31;
   font-weight: 700;
}
#game-board{

  width: 1200px;
}
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <link href="css/style.css" rel="stylesheet" type="text/css">

      <title>Memory card game</title>
   </head>
   <body>
      <header>
         <h1>Memory Game</h1>
      </header>
      <nav>
         <p><a href="#">INSTRUCTIONS</a><a href="#"> GAME</a></p>
      </nav>
      <main>
         <h2>INSTRUCTIONS</h2>
         <p>Concentration, also known as Match Match, Memory, Pelmanism, Shinkei-suijaku, Pexeso or simply Pairs, is a card game in which all of the cards are laid face down on a surface and two cards are flipped face up over each turn. The object of the game is to turn over pairs of matching cards.</p>
         <div id="game-board" class="board clearfix"></div>
      </main>
      <footer>
          <div class="clearfix">
          <p class="copyright">Copyright 2017</p>
          <p class="message">Created with &hearts; by <span class="name">GA</span></p>
              </div>
      </footer>
    <script src="js/main.js"></script>
   </body>
</html>

I want to know how I can turn back to its original position BOTH cards that didn't match. If there is a match, there is an alert saying congrats you win, OTHERWISE try again, but i want that two cards to return to its original position if didnt match. BUT ONLY ONE CARD TURN BACK TO ITS ORIGINAL POSITION(the one with the this , but I thought the this refers to both) The card images are not in here. Can someone help with this please?

var cards = [
  {
    rank: "Queen",
    suit: "Hearts",
    cardImage: "images/queen-of-hearts.png",
    id: 0,
  },
  {
    rank: "Queen",
    suit: "Diamonds",
    cardImage: "images/queen-of-diamonds.png",
    id: 1,
  },
  {
    rank: "King",
    suit: "Hearts",
    cardImage: "images/king-of-hearts.png",
    id: 2,
  },
  {
    rank: "King",
    suit: "Diamonds",
    cardImage: "images/king-of-diamonds.png",
    id: 3
  }
];
//1
function createBoard() {
  for (var i = 0; i < cards.length; i++) {
    var cardElement = document.createElement('img');
    // console.log(cardElement);
    cardElement.setAttribute('src', 'images/back.png');
    cardElement.setAttribute('data-id', i);
    document.getElementById('game-board').appendChild(cardElement);
    cardElement.addEventListener('click', flipCard);
    cardElement.style.width = '210px';

  }
}
createBoard();
//2
function flipCard () {
  var cardId = this.getAttribute('data-id');
  cardsInPlay.push(cards[cardId].rank);
  cardsInPlay.push(cards[cardId].id);
  this.setAttribute('src', cards[cardId].cardImage);

// CHECK FOR MATCH HERE =>
    if (cardsInPlay.length === 2) {
      if (cardsInPlay[0] === cardsInPlay[1]) {
        alert("You found a match!");
      }
      else {
        alert("Sorry, try again.");
        console.log(cardsInPlay);
        cardsInPlay[0].setAttribute('src', 'images/back.png'); // this doesnt work
        cardsInPlay[1].setAttribute('src', 'images/back.png'); // this doesnt work
      }
    }
}
var cardsInPlay = [];
body{
    text-align: center;
    margin: 0;

}

h1 {
    font-family: "Raleway", sans-serif;
    font-weight: 400;
    color: #0d2c40;
    font-size: 45px;
    letter-spacing: 1px;
    margin: 0;
    color: white;
}

p {
  font-family: "Droid Serif", serif;
  line-height: 26px;
  font-size: 18px;
}

a {
    font-family: raleway;
    text-decoration: none;
    color: #F15B31;
    letter-spacing: 1px;
    font-weight: 600;
    font-size: 18px;

}

h2 {
    font-family: raleway;
    font-size: 20px;
    color: #0d2c40;
    letter-spacing: 1px;
    font-weight: 600;
}

header {
    background-color: #F15B31;
    padding: 30px 20px 30px 20px;
}

main {
  width: 850px;
  margin: 35px auto
}

a {
    margin: 0 20px;
    color: white;
}

nav a:hover {
    border-bottom: 2px solid white;
}

nav {
    background-color: #00A6B3;
    padding: 20px 0;
}

img {
    margin: 40px 8px 0 8px;
}

footer {
    text-transform: uppercase;
    padding: 0 20px;
    background-color: #0D2C40;
    color: white;
    letter-spacing: .08em;
    font-weight: 500;
}

.copyright {
    float: left;
}

.message {
    float: right;
}

.clearfix:after {
  visibility: hidden;
  display: block;
  content: " ";
  clear: both;
  height: 0;
  font-size: 0;
}

.name {
   color: #F15B31;
   font-weight: 700;
}
#game-board{

  width: 1200px;
}
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <link href="css/style.css" rel="stylesheet" type="text/css">
      
      <title>Memory card game</title>
   </head>
   <body>
      <header>
         <h1>Memory Game</h1>
      </header>
      <nav>
         <p><a href="#">INSTRUCTIONS</a><a href="#"> GAME</a></p>
      </nav>
      <main>
         <h2>INSTRUCTIONS</h2>
         <p>Concentration, also known as Match Match, Memory, Pelmanism, Shinkei-suijaku, Pexeso or simply Pairs, is a card game in which all of the cards are laid face down on a surface and two cards are flipped face up over each turn. The object of the game is to turn over pairs of matching cards.</p>
         <div id="game-board" class="board clearfix"></div>
      </main>
      <footer>
          <div class="clearfix">
          <p class="copyright">Copyright 2017</p>
          <p class="message">Created with &hearts; by <span class="name">GA</span></p>
              </div>
      </footer>
    <script src="js/main.js"></script>
   </body>
</html>
fran
  • 169
  • 5

3 Answers3

1

EDIT: your problem with this is about closure in javascript. I recommend you use IIFE (for EcmaScript5) or let keyword (for EcmaScript6). Read more here.

Instead of doing this:

function createBoard() {
  for (var i = 0; i < cards.length; i++) {
    var cardElement = document.createElement('img');
    [..]
    cardElement.addEventListener('click', flipCard); << 'this' will refer to last cardElement at the end of the loop

Do this:

function createBoard() {
  for (var i = 0; i < cards.length; i++) {
    var cardElement = document.createElement('img');
    [..]
    cardElement.addEventListener('click', (function(x) {return function() {flipCard(x)}})(i)); // 'i' is immediately evaluated to the correct value
    cards[i].element = cardElement; // Keep association with DOM here

Now you can flip cards back easily.

function flipCard (i) {
  cardsInPlay.push(i);
  // Flip played card
  cards[i].element.setAttribute('src', cards[i].cardImage);

  if (cardsInPlay.length === 1)
    return; // First card: no game resolution yet

  // Second card: give user 1s to see it flipped before flipping back
  setTimeout(function(){
    if (cards[cardsInPlay[0]].rank === cards[cardsInPlay[1]].rank)
      alert("You found a match!");
    else
      alert("Sorry, try again.");
    cardsInPlay.forEach(function(i) {
      cards[i].element.setAttribute('src', 'images/back.png');
    });
    cardsInPlay.length = 0;
  }, 1000);
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
RaphaMex
  • 2,781
  • 1
  • 14
  • 30
  • Okay gonna try, but why when i click on two cards, in console.log i only see the last one clicked? i THOUGHT this refers to the one i click i dont get why doesnt work. But thank you very much >:) – fran Nov 30 '17 at 14:46
  • Even more simply, `cardsInPlay` can store the indexes (i.e. ids) of the cards. So you do not need to pass your objects around, – RaphaMex Nov 30 '17 at 14:48
  • Finally I updated pushing all in array `cardsInPlay`. It makes code simpler. – RaphaMex Nov 30 '17 at 15:12
  • Let me know if this still bothers you. If so, you can opt for a closure and IIFE: `cardElement.addEventListener('click', (function(x) {return function() {flipCard(x)}})(i));` – RaphaMex Nov 30 '17 at 15:56
  • Yes, stills bother haha. im just starting with JS so i dont know much, i jst want a very simple solution. Can you check the code? I updated, i put ids to each one and push it as well, but my concern is how I can update the 2 images to BACK.PNG, the problem is that i cannot do cardsInPlay[0].setAttribute('src', 'images/back.png'); cardsInPlay[1].setAttribute('src', 'images/back.png'); BECAUSE says is not a function, and the this only refers to the last card clicked so even if i put ids i dont know how to do it. Thank you very much in advance :) – fran Nov 30 '17 at 16:02
  • There you go. I suggest you start again from my code to make it easier. Enjoy closures with Javascript, it's powerful when you get it!! – RaphaMex Nov 30 '17 at 16:56
1

If you are trying to flip both cards back, this code only flips the last card in play "cardsInPlay[1]":

this.setAttribute('src', 'images/back.png');

What you want is to flip both "cardsInPlay[0]" and "cardsInPlay[1]" so maybe somethign like this:

else {
    alert("Sorry, try again.");
    console.log(cardsInPlay);
    cardsInPlay[0].setAttribute('src', 'images/back.png');
    cardsInPlay[1].setAttribute('src', 'images/back.png');
  }
Joel Cruz
  • 27
  • 1
  • 10
  • No cause appears this > TypeError: cardsInPlay[0].setAttribute is not a function I alreay tried and only works if i apply setAttribute to THIS. Sorry im new with this – fran Nov 30 '17 at 14:56
  • Joel Cruz, as i said that doesnt work, but WHY the this refers to the last card clicked? – fran Nov 30 '17 at 15:01
  • @fran It only flips one card because when you run it the first time "cardElement.addEventListener('click', flipCard);" it goes through and never triggers the if statement "if (cardsInPlay.length === 2)" and then it goes the second time and runs it on the current card. Best thing to do is store the ID of the card as RaphaMex said in his answer. – Joel Cruz Nov 30 '17 at 15:12
  • I tried but i dont know how to do it in a very simple way. im just starting with JS so i dont know much, i jst want a very simple solution. Can you check the code? I updated, i put ids to each one and push it as well, but my concern is how I can update the 2 images to BACK.PNG, the problem is that i cannot do cardsInPlay[0].setAttribute('src', 'images/back.png');cardsInPlay[1].setAttribute('src', 'images/back.png');BECAUSE says is not a function, and the this only refers to the last card clicked so even if i put ids i dont know how to do it. Thank you very much in advance :) – fran Nov 30 '17 at 16:05
0

The below snippet is modified to achieve the required functionality! can you please check?

var cards = [
  {
    rank: "Queen",
    suit: "Hearts",
    cardImage: "http://via.placeholder.com/350x150?text=QueenHeartsfront"
  },
  {
    rank: "Queen",
    suit: "Diamonds",
    cardImage: "http://via.placeholder.com/350x150?text=QueenDiamondsfront"
  },
  {
    rank: "King",
    suit: "Hearts",
    cardImage: "http://via.placeholder.com/350x150?text=KingHeartsfront"
  },
  {
    rank: "King",
    suit: "Diamonds",
    cardImage: "http://via.placeholder.com/350x150?text=KingDiamondsfront"
  }
];
//1 CREATE BOARD
function createBoard() {
  for (var i = 0; i < cards.length; i++) {
    var cardElement = document.createElement('img');
    // console.log(cardElement);
    cardElement.setAttribute('src', 'http://via.placeholder.com/350x150?text=back');
    cardElement.setAttribute('data-id', i);
    document.getElementById('game-board').appendChild(cardElement);
    cardElement.addEventListener('click', flipCard);
    cardElement.style.width = '210px';
  }
}
createBoard();
var prev = "";
//2 FLIPCARD
function flipCard () {
  var cardId = this.getAttribute('data-id');
  cardsInPlay.push(cards[cardId].rank);
  this.setAttribute('src', cards[cardId].cardImage);
  console.log(cardsInPlay[0]);
  console.log(cardsInPlay[1]);
    if (cardsInPlay.length === 2) {
      if (cardsInPlay[0] === cardsInPlay[1]) {
        alert("You found a match!");
        cardsInPlay = [];
      }
      else {
        alert("Sorry, try again.");
        cardsInPlay = [];
        // cardsInPlay.pop();
        // cardsInPlay.pop();
        // console.log(cardsInPlay);
        try{
        prev.setAttribute('src', 'http://via.placeholder.com/350x150?text=back');
        }catch(e){}
        this.setAttribute('src', 'http://via.placeholder.com/350x150?text=back');
      }
    }
    prev = this;
}
var cardsInPlay = [];
body{
    text-align: center;
    margin: 0;

}

h1 {
    font-family: "Raleway", sans-serif;
    font-weight: 400;
    color: #0d2c40;
    font-size: 45px;
    letter-spacing: 1px;
    margin: 0;
    color: white;
}

p {
  font-family: "Droid Serif", serif;
  line-height: 26px;
  font-size: 18px;
}

a {
    font-family: raleway;
    text-decoration: none;
    color: #F15B31;
    letter-spacing: 1px;
    font-weight: 600;
    font-size: 18px;

}

h2 {
    font-family: raleway;
    font-size: 20px;
    color: #0d2c40;
    letter-spacing: 1px;
    font-weight: 600;
}

header {
    background-color: #F15B31;
    padding: 30px 20px 30px 20px;
}

main {
  width: 850px;
  margin: 35px auto
}

a {
    margin: 0 20px;
    color: white;
}

nav a:hover {
    border-bottom: 2px solid white;
}

nav {
    background-color: #00A6B3;
    padding: 20px 0;
}

img {
    margin: 40px 8px 0 8px;
}

footer {
    text-transform: uppercase;
    padding: 0 20px;
    background-color: #0D2C40;
    color: white;
    letter-spacing: .08em;
    font-weight: 500;
}

.copyright {
    float: left;
}

.message {
    float: right;
}

.clearfix:after {
  visibility: hidden;
  display: block;
  content: " ";
  clear: both;
  height: 0;
  font-size: 0;
}

.name {
   color: #F15B31;
   font-weight: 700;
}
#game-board{

  width: 1200px;
}
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <link href="css/style.css" rel="stylesheet" type="text/css">
      
      <title>Memory card game</title>
   </head>
   <body>
      <header>
         <h1>Memory Game</h1>
      </header>
      <nav>
         <p><a href="#">INSTRUCTIONS</a><a href="#"> GAME</a></p>
      </nav>
      <main>
         <h2>INSTRUCTIONS</h2>
         <p>Concentration, also known as Match Match, Memory, Pelmanism, Shinkei-suijaku, Pexeso or simply Pairs, is a card game in which all of the cards are laid face down on a surface and two cards are flipped face up over each turn. The object of the game is to turn over pairs of matching cards.</p>
         <div id="game-board" class="board clearfix"></div>
      </main>
      <footer>
          <div class="clearfix">
          <p class="copyright">Copyright 2017</p>
          <p class="message">Created with &hearts; by <span class="name">GA</span></p>
              </div>
      </footer>
    <script src="js/main.js"></script>
   </body>
</html>
Naren Murali
  • 19,250
  • 3
  • 27
  • 54