"Image gallery" assessment

Hi there, I have a question regarding my version:

var displayedImage = document.querySelector('.displayed-img');
var thumbBar = document.querySelector('.thumb-bar');

btn = document.querySelector('button');
var overlay = document.querySelector('.overlay');

for(var i = 1; i < 6; i++){
  var newImage = document.createElement('img');
  newImage.setAttribute('src', "images/pic" + i + ".jpg");
  thumbBar.appendChild(newImage);
};

thumbBar.addEventListener('click', function(e){
	var imgSrc = e.target.getAttribute('src');
	displayedImage.setAttribute('src', imgSrc);
});

So I added the eventListener to “thumbBar”, rather than to its child “newImage” as in finished example, and in this way avoided mentioning it in the loop altogether. It works as intended and I spotted no errors, but I would like to know if this version is consistent with the standards and can be used alongside with yours. Thanks! :slight_smile:

Hey there!

Yes, this works well, due to event bubbling. I think I didn’t implement like that originally because I wanted to keep things more obvious, but I don’t think it actually makes a lot of difference.

Nice work.

Hello everyone,

I feel so bad about it but I gave up on this assignment and looked at the example code.

The reason I gave up is because I got so confused that I could not continue any more yet I knew I was going in the right direction. I knew that I had to and how to create the loop and use the even object but I just got stuck on one part.

I am going to explain my confusion with the “looping through the images and event handler” part only as I have not yet done the darkening effect part.

  1. I found the “Steps to complete” the most confusing. For example, in the first section of the “Adding an onclick handler to each thumbnail image”, in this part - “This can be done by running the getAttribute() function on the <img> in each case …” - I could not understand why the function would run on the <img> which is as I understand a different element in the html located in the full-img div when the newImage is the one we need with a location in the thumb-bar div. My question is why is the <img> mentioned here at all when all this section wants us to do is create the following code where <img> or full-img div is not even mentioned; newImage.onclick = function(e) {

var imgSrc = e.target.getAttribute(‘src’);

Please correct me if I am wrong about this.

  1. This part - “Run a function, passing it the returned src value as a parameter. You can call this function whatever you like.” - I would have probably figured out somehow if I had been a bit more patient and not gotten stuck with the section above.
  2. The same with the third section.

Since I was doing this all on my on my Iphone, I had to store all the images on an external server online which gave me links to them. So I created an array with the links and accessed it with the loop thus assigning them as attributes to newImage. However, it does not seem to work. Can you please explain why;

Here’s my code;

for ( i = 0; i = 4; i++ ) {

var newImage = document.createElement(‘img’);

var images = [“https://s33.postimg.cc/71rt7bggv/pic1.jpg”, “https://s33.postimg.cc/4kg202bzz/pic2.jpg”,

https://s33.postimg.cc/tqh06w5kf/pic3.jpg”,

https://s33.postimg.cc/xa2xwpnpr/pic4.jpg”,

https://s33.postimg.cc/5mq8ima8v/pic5.jpg”];

newImage.setAttribute(‘src’, images[i]);

thumbBar.appendChild(newImage);

newImage.onclick = function(e) {

var imgSrc = e.target.getAttribute(‘src’);

displayImage(imgSrc);

}

}

function displayImage(imgSrc) {

displayedImage.setAttribute(‘src’, imgSrc);

Another question that still boggles me is that it seems to be okay to call a function and define it later. Not only that but also call a function inside a scope closed by braces which is the loop and define it later outside of that scope. To my knowledge, this contradicts some of the lessons on JS here. I know Chris sent a link for an explanation earlier but since the content there is a lil advanced, I could not understand it. I would appreciate a simple explanation.

By the way, could anyone let me know how long it took them to do this whole assignment? A few hours or days? I was so impatient that I looked at the example after having re-read the steps to complete 3 or 4 times and still remaining confused about it. Is it best to just leave it for a while and get back to it with a fresh mind?

Special thanks to Chrismills and everyone trying to help others who have a hard time grasping the assignment.

Thank you!!!

Hi there @askaroff5131! Sorry for not replying so long, but I have been on holiday.

So I will try to answer your questions one by one, and see if I can clear up this confusion.

  1. In each loop iteration, newImage is an <img> element we have created and then appended inside the thumb-bar div. Earlier on in the loop we create this image and set its src attribute to the value of one of the images we want to show as a thumb. In the event handler we attach to each image, we retrieve that very same src value using getAttribute(), and then pass it to the displayImage() function. This function sets the src of the displayedImage (the main big image) to equal this passed src value. So when you click a thumb, the main display image shows the same image.

  2. and 3. OK, fair enough. I think the above explanation should help.

iPhone — wow, you are doing this all on your iPhone? This is impressive!

Sample code — your code wasn’t working because first of all, you were creating an infinite loop by setting your exit condition to i = 4. If you change this to i < 5, you should get a better result. Also, your displayImage() function needs a closing bracket at the end of it — }. You could put your array outside the loop too — you only need to create this once. Apart from that it looks OK.

Why is it OK to call a function and then define it later? Because of execution order — when the browser interprets JS code, it will look at the functions first, make sure they are OK and able to run successfully, before then running other code that relies on those functions.

How long to complete an assignment? I’d say a few hours at most. I think that if you are struggling after a couple of hours, it is OK to go and look up the sample code, see how it works, then try to recreate it from memory. There is no point sitting there being frustrated for ages.

Hello Chris, thank you for your assistance! Much appreciated.

My code has finally worked. To be honest, this was not an easy task.

Especially, the creation of the function (DisplayImage) part was quite difficult to comprehend for me.

If you happen to have time to answer the following quick question, I would be grateful;

Why does the exit condition, i = 4, create an infinite loop?

Thank you in advance.

Have a great week!

/* Looping through images */

for (var i = 1; i <= 5; i++) {
  var newImage = document.createElement('img');
  newImage.setAttribute('src', "images/pic" + [i] + ".jpg");
  thumbBar.appendChild(newImage);

  
  function displayImage(e) {
    var getImage = e.target.getAttribute("src");
    displayedImage.setAttribute("src", getImage);
  }

  newImage.addEventListener('click', displayImage);
}

/* Wiring up the Darken/Lighten button */

function overlayBg() {
  getBtnAtt = btn.getAttribute("class");

  if (getBtnAtt === "dark") {
    btn.setAttribute("class", "light");
    btn.textContent = "Lighten";
    overlay.style.backgroundColor = "rgb(0, 0, 0, 0.5)";
  } else {
    btn.setAttribute("class", "dark");
    btn.textContent = "Darken";
    overlay.style.backgroundColor = "rgb(0, 0, 0, 0)";
  }
}

btn.addEventListener('click', overlayBg);

The idea of an exit condition is that it defines a condition that is:

  1. true when the loop begins running
  2. false at some point later, at which point the loop stops running

So if it is set to i < 5 and i starts at 0, the loop will begin running because i is currently less than 5. When i gets to 5, the loop will stop running.

If it is set to i = 4 and i starts at 0, the loop will begin running but the condition will return false at the very beginning. This causes it to run infinitely, for reasons I’m not really very clear on. :wink:

It is a bit of a weird infinite loop situation. Normally they will keep running because the exit condition will always return true, as in these examples: http://www.scriptingmaster.com/javascript/infinite-loops.asp

Hi,

Thanks for your great support. I have a question regarding the “displayedImage” element. surprisingly I’m not able to add an event listener or onclick event to that specific object. Could you please check and let me know what is wrong with my code?

for (var i = 0; i < 5; i++) {
  imgUrl = 'images/pic'+(i+1)+'.jpg';
  var newImage = document.createElement('img');
  newImage.setAttribute('src', imgUrl);
  thumbBar.appendChild(newImage);

  newImage.addEventListener ('click', function(e){
    console.log('image url is: '+e.target.getAttribute('src'));
    displayedImage.setAttribute('src', e.target.getAttribute('src'));
  } );

}

displayedImage.addEventListener ('click', console.log('hi'));

Thanks in advance.

OK I got it. It is because the “overlay” div covers “newImage” (the big image’s div). Now how can I access a “div” beneath another one?

Cool, glad you figured it out! Sorry for the slowness in replying, but I was at a workweek last week.

So if I understand your question correctly, you are asking how to interact with an element that is stacked below another one in the stacking order (i.e. as controlled by z-index?)

Well, there is not really a way to click on it directly. its “hit area” is effectively hidden. You could create a button on the page somewhere else that when pressed controls the element in question. Or you could program a keyboard shortcut that does something with it, or add it to the tab index of the page using the tabindex attribute.

Both of these techniques are explained in https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Building_in_keyboard_accessibility

1 Like

Thank you so much for your help. and no worries for the timing :wink: I really appreciate all the helps.

var displayedImage = document.querySelector(’.displayed-img’);
var thumbBar = document.querySelector(’.thumb-bar’);

btn = document.querySelector(‘button’);
var overlay = document.querySelector(’.overlay’);

/* Looping through images */

var pic = [‘pic1.jpg’, ‘pic2.jpg’, ‘pic3.jpg’, ‘pic4.jpg’, ‘pic5.jpg’];
for (let i = 0; i < pic.length; i++) {
pic += pic[i];
}
return pic

var newImage = document.createElement(‘img’);
newImage.setAttribute(‘src’, pic);
thumbBar.appendChild(newImage);

/* Wiring up the Darken/Lighten button */

btn.onclick = function(a);
{
btn.setAttribute(‘class’, overlay);
btn.textContent = Darken;
overlay.style.backgroundColor = “rgba(0,0,0,0.5)”;
}

btn.onclick = function(b);
{
btn.setAttribute(‘class’, overlay);
btn.textContent = lighten;
overlay.style.backgroundColor = “rgba(0,0,0,0)”;
}

Hi @hahawill — I tried reviewing your code, but it seems incomplete and doesn’t work. Has this pasted correctly into discourse, or is there some of it missing? Do you have your code available somewhere else, like on GitHub for example?

Hello I was doing the image gallery assessment and I have a question. when looping through the images I did not use an event object to add the source of the images to the displayedImage variable instead I did this and it works too.

newImage.onclick = () => displayedImage.setAttribute(‘src’,‘images/pic’+i+’.jpg’);
Can anyone tell me if this is a good way to do it or not I would like know. Thank you

Hi @nelson_hernandez!

So just to check, are you saying that your loop is written like this:

for(var i = 1; i <= 5; i++) {
  var newImage = document.createElement('img');
  newImage.setAttribute('src', 'images/pic' + i + '.jpg');
  thumbBar.appendChild(newImage);
  newImage.onclick = () => displayedImage.setAttribute('src','images/pic'+i+'.jpg');
}

?

This looks like it should work, but it actually won’t because loops tend to run through all iterations before functions, event handlers, etc. inside them are then run. So when you do something like this, you’ll end up with i inside every handler function set to the same value.

To avoid this issue, in our example we’ve instead grabbed the correct src value that should be set for the displayed image from the thumbnail that was just clicked, using e.target.getAttribute('src'):

for(var i = 1; i <= 5; i++) {
  var newImage = document.createElement('img');
  newImage.setAttribute('src', 'images/pic' + i + '.jpg');
  thumbBar.appendChild(newImage);
  newImage.onclick = function(e) {
    var imgSrc = e.target.getAttribute('src');
    displayImage(imgSrc);
  }
}

function displayImage(imgSrc) {
  displayedImage.setAttribute('src', imgSrc);
}

Or are you doing something different?

Thanks!

Thank you so much for the explanation I will use the event.target property instead.

Hello everyone. I’d like to get a mark for this assessment. I got numerous issues to make the thumbnails displayed but I get it. I don’t know if that is what we had to do. so please check my js code:

Hi there @nikhma99,

Thanks for sending your code in. I’ve had a look, and it seems to work fine. I think the main thing you could improve on here is the loops — you don’t need to giant if statement in there, because you can instead derive the src value from the i value; something like 'img/pic' + (i + 1) + '.jpg'.

To learn more about what we did, see the following links:

thank you very much. i’ll work on it.

var displayedImage = document.querySelector('.displayed-img');
var thumbBar = document.querySelector('.thumb-bar');

btn = document.querySelector('button');
var overlay = document.querySelector('.overlay');

/* Looping through images */
for (let i = 1; i < 6; i++) {
  var newImage = document.createElement('img');
  let pathToImg = 'images/pic' + i + '.jpg'
  newImage.setAttribute('src', pathToImg);
  thumbBar.appendChild(newImage);

  newImage.addEventListener('click', switchImage);
}

function switchImage(e) {
  displayedImage.setAttribute('src', e.target.getAttribute('src'));
}

/* Wiring up the Darken/Lighten button */
btn.onclick = function () {
  if(btn.getAttribute('class') === 'dark') {
    btn.setAttribute('class', 'light');
    btn.innerHTML = 'Lighten';
    overlay.style.backgroundColor = "rgba(0,0,0,0.5)";
  } else {
    btn.setAttribute('class', 'dark');
    btn.innerHTML = 'Darken';
    overlay.style.backgroundColor = "rgba(0,0,0,0)";
  }
}

I just want to ask for your opinion on my code. Like, is there any thing I need to fix?