Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Robert McCormick
Robert McCormick
4,400 Points

Assigning array index values to img src: What am I doing wrong?

I have been going through the Front End Development track, and I decided to make a simple matching game to practice the Javascript/JQuery I've been learning. I want to have 16 "cards", which will be flipped to reveal the underlying images, but I am having a lot of trouble assigning different images to each individual card. I have been racking my brain for days now, trying every which way I can imagine to make it work, but I am stuck. I am hoping somebody here will point me in the right direction.

I created a container "gameBoard" div in the html file, and then created the rest of the structure dynamically with the below javascript. I have copied my latest attempt at creating the cards with the function $createGameCards.

My problem is this: I want assign the images from the $gameImagesUsed array to each <img> src attribute, using each index value only once, but everything I have tried has ended up assigning the same value to all the src attributes. What should I be doing differently?

Thanks in advance for any help you can give me.

var $imagePool = ['earlyvegetarians.jpg', 'desmond.jpg', 'Desmond - Long Way to the Top.jpg', 'Prince Eric Gainz.jpg'];
var $gameImagesUsed = [];

//Add 4 copies of each image from $imagePool to the $gameImagesUsed array.

$populateImagesToBeUsed = function () {
    counter = 0;
    do {
        for (i = 0; i < 4; i++) {
            $gameImagesUsed.push($imagePool[i]);
        }
        counter ++;
    } while (counter < 4);
}

$populateImagesToBeUsed();

//Create cards here

$createGameCards = function () {
  for (j = 0; j < 16; j++) {
    $('#gameBoard').append('<div class="front"></div><div class="back"></div>');
    $('.back').append('<img>');

  n = 1;

  for (index = 0; index < $gameImagesUsed.length; index ++) {
    $('#gameBoard:nth-child(n) img').attr('src', 
      $gameImagesUsed[index]);
    n++;
  }
}

$createGameCards();
<div id="gameBoard">
  <div class="gameCard"> // (x16 of these gameCard divs)
    <div class="front"></div>
    <div class="back">
      <img>
    </div>
  </div>
</div>
Robert McCormick
Robert McCormick
4,400 Points

Wow... the formatting was even worse than I expected. Why does it look like this? It even omitted and changed some of the content.

Hey Robert,

Your code didn't paste correctly as a lot of your code is missing. If you're working on this in Workspaces, can you post a snapshot of your workspace in a new comment? If you don't know how to do that, you can check out this post: http://www.teamtreehouse.com/forum/workspace-snapshots.

If you're not working on your code in Workspaces, you'll have to reformat your code and wrap each section of your code in 3 backticks as seen in the Markdown Cheatsheet and in the image below. Put a blank line above and below each set of backticks.

code

The reason why most of the code is stripped out is because all < and > tags are stripped from content. The reason for this is to prevent JavaScript injection into the Treehouse server. When you wrap your code in backticks, though, each < and > is made into an HTML entity and applied formatting/colors so that it looks nice. Each time I put a < sign, I'm using the HTML entity for it i.e. & lt; (put the & and lt; together). However, you don't need to do this for your code if you just wrap it in backticks as shown above.

Robert McCormick
Robert McCormick
4,400 Points

Thanks, Marcus! I appreciate your help with the formatting. That's good to know!

2 Answers

Hey Robert,

I messed around with your Workspace and got the images to work. You had a couple things I changed for efficiencies' sake and there were a few errors with your code that wasn't letting you do what you wanted to do. When you were trying to assign the src to each cardImage, you weren't concatenating the strings correctly. Your concatenation looked like this $('#cardImage" + j"').attr('src', $gameImagesUsed[j]);. Anytime you are pushing a few items together, you always end the string with the beginning quote. You might have been tired or something, though, so all is forgiven! haha :D

Check out what I did in your Workspace. I commented out a few lines of CSS in the Workspace that dealt with absolute positioning so I could make sure I saw all 4 pictures appear in the game area. All you have to do to remove those comments is click anywhere on the line and press Ctrl + /. It'll toggle between commenting out the line and removing the comment. Just look for lines of code that are commented out and do the Ctrl + / command on them.

I made the loop inside $createGameCards() more modular as well, since you really don't want to use a static number for iterating over an array. Always use the array's length.

I changed the names of a couple files that had spaces in them to a short version. It's best to avoid spaces in your file names and instead use - or _ as a spacer i.e. "desmond_long_way_to_the_top.jpg".

Here's the Workspace: https://w.trhou.se/isexa0nspt

Robert McCormick
Robert McCormick
4,400 Points

Thank you so much, Marcus! This is exactly what I was trying to accomplish. I really appreciate your help, and also the tips/best practices. Now I can move on to the actual game logic, and begin styling everything with css. This deal with the images has had me stumped for a week; I can't thank you enough for your help.

My pleasure, Robert! I can't wait to see what you come up with. Whenever you get it finished, you should definitely post it here on the forums, and if you can remember, tag me on here so I can see it! :) Happy Coding!

Alrighty, Robert. I would go about it a little bit differently so that you can target each image separately. See if this works for you (I'm adding comments for clarity):

var $createGameCards = function () {
    for (var j = 0; j < 16; j++) {
        $('#gameBoard').append('<div class="front"></div><div class="back"></div>');
        //Added id to each image based on the current number in loop
        $('.back').append('<img id="card' + j + '">');
    }
    //Took for loop out of nest
    for (var index = 0; index < $gameImagesUsed.length; index ++) {
        //Target each individual image and set its src to each index in the $gameImagesUsed array
        $('#card'+index).attr('src', $gameImagesUsed[index]);
    }
}
$createGameCards();
Robert McCormick
Robert McCormick
4,400 Points

Thanks, Marcus. The solution you gave me didn't do what I needed as written, but it has helped me get moving again. Your idea to assign id's to the images has me feeling like I'm on the right track now, but I'm still having problems assigning only one image to the divs with the class ".back". I've tried everything I can think of using the insight you provided yesterday, but now I'm feeling stuck again.

I'm trying to target the child div class="back" of each div id="card - " class="gameCard", and then append an img with src=$gameImagesUsed[someIndexValue] , but nothing I've tried works. I'm not necessarily looking for a solution, as all this trial and error is really helping me become more comfortable and familiar with the language, so any suggestions are very much welcome. If anybody has any ideas I could try, I would greatly appreciate it.

var $imagePool = ['earlyvegetarians.jpg', 'desmond.jpg', 'Desmond - Long Way to the Top.jpg', 'Prince Eric Gainz.jpg'];
var $gameImagesUsed = [];

//Add 4 copies of each image from $imagePool to the $gameImagesUsed array.

$populateImagesToBeUsed = function () {
    counter = 0;
    do {
        for (i = 0; i < 4; i++) {
            $gameImagesUsed.push($imagePool[i]);
        }
        counter ++;
    } while (counter < 4);
}

$populateImagesToBeUsed();


//Fischer-Yates shuffle algorithm

function $randomize() {
    var tracker = $gameImagesUsed.length, temp, index;

    while (tracker > 0) {
        index = Math.floor(Math.random() * tracker);
    tracker --;

    temp = $gameImagesUsed[tracker];
    $gameImagesUsed[tracker] = $gameImagesUsed[index];
    $gameImagesUsed[index] = temp;
    }
return $gameImagesUsed;
}

$randomize();

console.log($gameImagesUsed);

//$gameImagesUsed has been shuffled.


$createGameCards = function () {

        for (var j = 0; j < 16; j++) {
        $('#gameBoard').append('<div id="card' + j + '" class="gameCard"></div>');
        }
    $('.gameCard').append('<div class="front"></div><div class="back"></div>');

        /*for (var j = 0; j < 16; j++) {
            $('"#card' + j + '" .back').append('<img id="card' + j + '">');
        }*/

    for (var j = 0; j < 16; j++) {
        id = $("#card0");
        var idSelect = function () {
            if (parseInt(id) === j) {
                id.children('.back').append('<img id="image' + j + '">');
            }
        }
        idSelect();
         }
}

$createGameCards();

This is how I'd like the html to look:

<div id="gameBoard">
  <div class="gameCard"> // (x16 of these gameCard divs)
    <div class="front"></div>
    <div class="back">
      <img src="$gameImagesUsed[index value]">
    </div>
  </div>
</div>

I see what you're doing now. For some reason, I thought there was only one div with the class of back lol I was tired yesterday and that's my excuse! :D You just need to apply the same principles to each "back" div as I did with the id's. Are you working on this in a workspace, Robert? If you are, I'd really like to get a snapshot of this so that I can have access to the resources you're using in your application.

Robert McCormick
Robert McCormick
4,400 Points

I've just been using Notepad while working on stuff on my work computer, and I use Sublime Text when I get home. It looks like I need to start using Workspaces more, though, as it seems like it would really help simplify things, especially when I need some help! I'll go ahead and move the files for this project to Workspaces, and I'll let you know as soon as I have that snapshot.

Also, I think I made a mistake when I pasted my code yesterday, which is why it looked like there was only one .back div; I accidentally omitted the .gameCard div creation in the JS code.

Thanks again for your help.

Sounds good, Robert!

Robert McCormick
Robert McCormick
4,400 Points

Alright.. I did some more rework today, and here is a snapshot of how it currently looks. I've added comments just before the $createGameCards function to explain what my problem is exactly. I can't get the last line of the function to work; I can't figure out how to select the id of each img tag based on the loop iteration. It seems like it would work, though, if the loop could progress past that sticking point. Let me know what you think.

Thanks again, Marcus!

https://w.trhou.se/ea0xosd8d9