0

I just started learning javascipt and am stumped at this error in the middle of a tutorial:

I'm trying to create a mini-game of sorts where I flip cards and find matches.

I have objects in an array and am trying to call the particular value of 'rank' depending on which card(object) is chosen.

Running the code in console gives me an error: Uncaught TypeError: Cannot read property 'rank' of undefined.

Javascript:

console.log("Up and running");

var cards = [
{
    rank: "queen",
    suit: "hearts",
    cardImage: "images/queen-of-hearts.png"
},
{
    rank: "queen",
    suit: "diamonds",
    cardImage: "images/queen-of-diamonds.png"
},
{
    rank: "king",
    suit: "hearts",
    cardImage: "images/king-of-hearts.png"
},
{
    rank: "king",
    suit: "diamonds",
    cardImage: "images/king-of-diamonds.png"
}
];
var cardsInPlay = [];

var checkForMatch = function() {
    if (cardsInPlay[0] === cardsInPlay[1]) {
        alert("You found a match!");
    } else alert("Sorry, try again");
}
var flipCard = function(cardId) {
    console.log("User flipped " + cards[cardId].rank); 
    /*issue is with calling the rank*/
    console.log(cards[cardId].cardImage);
    console.log(cards[cardId].suit);
    cardsInPlay.push(cards[cardId].rank);
    if (cardsInPlay.length === 2) {
        checkForMatch();
    };
}

var createBoard = function() {
    for (var i = 0; i < cards.length; i ++) {
        var cardElement = document.createElement('img');
        cardElement.setAttribute("img", "images/back.png");
        cardElement.setAttribute("data-id", i);
        cardElement.addEventListener("click", flipCard());
        document.getElementById("game-board").appendChild(cardElement);
    }
}
createBoard();

flipCard(0);
flipCard(2);

Is my error due to the way I call the value from the object using cards[cardId].rank?

ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
Rebecca Tay
  • 331
  • 1
  • 11
  • 2
    flipcard function needs an cardId parameter, when you call `flipcard` on click event you don't pass any parameter, and it becomes undefined. – Gntem Apr 20 '17 at 09:27

3 Answers3

0

Try changing

cardElement.addEventListener("click", flipCard());

to

cardElement.addEventListener("click", function(){ flipCard(i); });

UPDATE start

to

cardElement.addEventListener("click", flipCard.bind(null, i));

to avoid closuring case mentioned in comments

UPDATE end

Explanation: when calling addEventListener, second argument must be a function, but you pass result of the call of the function flipCard, which returns undefined.

Another mistake in your code, is that you call it without arguments, while it expects cardId as argument, and when it does not get it, it takes undefined element from the cards array

Jevgeni
  • 2,556
  • 1
  • 15
  • 18
0

You have to pass a function reference to addEventListener (a function that call flipCard with a correct parameter). Then you'll have this problem which you can be solved like this:

var createBoard = function() {
    for (var i = 0; i < cards.length; i ++) {
        var cardElement = document.createElement('img');
        cardElement.setAttribute("img", "images/back.png");
        cardElement.setAttribute("data-id", i);

        // ############################################# 

        (function(index) {
            cardElement.addEventListener("click", function() {
                flipCard(index);
            });
        })(i);

        // ############################################# 

        document.getElementById("game-board").appendChild(cardElement);
    }
}

or using forEach instead of for which make things a lot simpler:

var createBoard = function() {
    cards.forEach(function(card, i) {
        var cardElement = document.createElement('img');
        cardElement.setAttribute("img", "images/back.png");
        cardElement.setAttribute("data-id", i);

        // no need to wrap this in an immediately invoked function expression (as this whole code is wrapped in the callback of forEach)
        cardElement.addEventListener("click", function() {
            flipCard(i);
        });

        document.getElementById("game-board").appendChild(cardElement);
    }
}
Community
  • 1
  • 1
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
0

Just update

cardElement.addEventListener("click", flipCard());

To

cardElement.addEventListener("click", function(e){ flipCard(e.target.dataset.id); });

Pravin Pareek
  • 19
  • 1
  • 2