2

I am creating a Matching Card game using jQuery. Currently, I am running into an issue where the playerChoices array in my code does not update the 'matched' cards with the 'matched' class.

var playerChoices = [];

function showCard(){

    $(this).addClass('selected'); //mark the selection with the selected class

    playerChoices.push($(this)); //push the players choice onto the playerChoices array
    console.log(playerChoices);

    moves++;
    console.log(moves);

    $('#buttons').show();
    matchCards(playerChoices);

}

Here is the function in question where the issues lie:

function matchCards(array){

    if(playerChoices.length === 3){
        //when the player finds the first match
        if(playerChoices[0].attr('class') === playerChoices[1].attr('class')){  //if both playerChoices have the class 
            console.log("match found at index 0 and 1 of playerchoice!");
            **$(playerChoices).each(playerChoices, function(index, element){
                $(this).addClass('matched');**
            })
        }

        //Deselect the two choices that were made
        else{ 
            $(playerChoices).each(function(index, element){
                $(this).removeClass('selected');
            })
            playerChoices = [];
        }
    }

    else if(playerChoices.length === 4){

        //when the player gets the second match
        if(playerChoices[2].attr('class') === playerChoices[3].attr('class')){
            console.log("match found at index 2 and 3 of playerchoice!");
            **$(playerChoices).each(playerChoices, function(index, element){
                $(this).addClass('matched');**
            })
            **showGameOverMessage();**
        }

        //Deselect the last two choices that were made
        else{
            $(playerChoices).each(function(index, element){
                $(this).removeClass('selected');
            })
        }
    }
}

The primary issue here are the area's that I have 'asterisks' around in my code. I set up break points in the console, and I found that the code was never reaching the $(this).addClass('matched') lines. I've never used .each before and have looked at the examples api.jquery.com but I still was not able to overcome this issue of applying the matched class to my 'matched' cards.

FYI: I tried to get my code to work in JSFiddle but I kept getting errors with the images of my cards. My code works outside of that, I am just not able to get the matching class to apply appropriately.

https://jsfiddle.net/2sharkp/54s47vzb/ Works now

Any help is greatly appreciated!

ziggy
  • 35
  • 5
  • Where do you ever *add* an entry to `playerChoices`? – T.J. Crowder May 22 '16 at 16:58
  • see my edits, i added my showCard() function – ziggy May 22 '16 at 17:01
  • _"I tried to get my code to work in JSFiddle"_ Can you post link to jsfiddle? What is `$(this)` expected to be within `.each()` callback? – guest271314 May 22 '16 at 17:04
  • $('.card').on('click', showCard); its a .card class that holds the card itself. EDIT: Just added a JSFiddle link. I was able to get over the image issues. But now its complaining about the jQuery script. – ziggy May 22 '16 at 17:04
  • @ziggy https://jsfiddle.net/xowkyh6p/1/ ? – guest271314 May 22 '16 at 17:09
  • for some reason, your link works, but mine does not. GAH – ziggy May 22 '16 at 17:23
  • @ziggy _"for some reason, your link works, but mine does not. "_ What do you mean by "but mines does not"? – guest271314 May 22 '16 at 17:37
  • The code works, which means the cards actually flip. The one I initially posted does not work because it was complaining about the jQuery script tag. Here is the error I see in the console... "Mixed Content: The page at 'https://jsfiddle.net/2sharkp/xowkyh6p/' was loaded over HTTPS, but requested an insecure script 'http://code.jquery.com/jquery-latest.min.js'. This request has been blocked; the content must be served over HTTPS. (index):163 Uncaught ReferenceError: $ is not defined" – ziggy May 22 '16 at 17:41
  • 1
    @ziggy Try explicitly using ` – guest271314 May 22 '16 at 18:06
  • @ziggy plnkr http://plnkr.co/edit/X0pYB3CA7GVbd7i6phbJ?p=preview – guest271314 May 22 '16 at 18:12
  • Hey, thanks for that plunker link. I'll definitely add that as a possible alternative. But I have the JSFiddle link properly turning my cards now. – ziggy May 22 '16 at 18:30

2 Answers2

3

Your updated question makes the problem clear: You're pushing jQuery instances into playerChoices:

playerChoices.push($(this));

...then later using $(playerChoices).each(...) to try to loop over them. While $() accepts arrays of HTML elements in the $() function, it doesn't correctly understand it if you pass it an array of jQuery instances — you end up with a jQuery instance wrapped around that set of jQuery instances, which isn't useful — you may as well just use the array (or use a single jQuery instance as I describe later).

You can use $.each (the one on the jQuery function itself):

$.each(playerChoices, function() {
    // ...`this` (not `$(this)`) here will be a jQuery instance:
    this.addClass('matched');
});

Updated Fiddle

But you really dont need $.each, just use the array's built-in forEach:

playerChoices.forEach(function(entry) {
    // ...`entry` here will be a jQuery instance
    entry.addClass('matched');
});

Updated Fiddle

...or there are lots of other ways to loop through arrays outlined in my answer here.

That said, you might consider making playerChoices a (single) jQuery instance. jQuery is set-based, so a single jQuery instance can contain multiple HTML elements that you can then act on with just a single method call. For instance, if you made playerChoices a jQuery instance, instead of:

playerChoices.forEach(function(entry) {
    entry.addClass('matched');
});

You could do this:

playerChoices.addClass('matched');

To do that, start with:

playerChoices = $();

...and add elements via add:

playerChoices.add(this);
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    But OP wraps array into jQuery object, which should be ok: `$(playerChoices)`. – dfsq May 22 '16 at 16:58
  • @dfsq: It is *if* the entries in `playerChoices` are HTML element instances. I can't tell from the code whether they are (that's the reason for the question on the question). If they *are* HTML elements, this is not the right answer. – T.J. Crowder May 22 '16 at 17:00
  • @TJCrowder The issue appears to be `playerChoices` at `$(playerChoices).each(playerChoices, ` before callback – guest271314 May 22 '16 at 17:00
  • @guest271314: Why would that be relevant? – T.J. Crowder May 22 '16 at 17:00
  • @T.J.Crowder Because `.each()` does not expect a variable before callback – guest271314 May 22 '16 at 17:01
  • @guest271314: I think I see what you mean, yeah, they're sort of trying to to use both `each` and `$.each` there. Probably happened as an edit when the first didn't work. – T.J. Crowder May 22 '16 at 17:04
  • $(playerChoices).each(**playerChoices**, function(index, element){ $(this).addClass('matched'); }) – guest271314 May 22 '16 at 17:06
  • $.each(playerChoices, function(){ $(this).addClass('matched'); }) like that? – ziggy May 22 '16 at 17:12
  • @ziggy: No (hit refresh, I do give examples in the answer), because `this` will *already be* a jQuery instance. That said, passing a jQuery instance through `$()` is harmless (it's just pointless). – T.J. Crowder May 22 '16 at 17:13
1

Try removing playerChoices before callback

$(playerChoices).each(function(index, element){
  $(this).addClass('matched');
})

jsfiddle https://jsfiddle.net/xowkyh6p/1/

guest271314
  • 1
  • 15
  • 104
  • 177