Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript jQuery Basics (2014) Creating a Simple Lightbox Perform: Part 4

Ashley Livingston
Ashley Livingston
6,931 Points

How would I add a next button to this lightbox to show the next image in my gallery?

I added a variable called nextButton, and appended it to the overlay early in the code. Then I added the following code at the bottom:

Clearly what's below is not working, but I'm just starting with jquery and don't what's what yet. Can someone point me in the right direection?

$nextButton.click(function() {
      var nextImageLocation = $(this).next().attr("href");
      $nextImage.attr("src", nextImageLocation);
      $overlay.detach($image);
      $overlay.append($nextImage);
  });
Gabriel Ward
Gabriel Ward
20,222 Points

Hi Ashley,

I'm trying to do the same thing that you were trying to do here. Did you figure out a solution in the end? I'd be grateful for any help. Trying to get my head around the .next() method. Cheers,

Gabe

Ashley Livingston
Ashley Livingston
6,931 Points

Hi Gabe, just added how I did it below.

4 Answers

Sergey Podgornyy
Sergey Podgornyy
20,660 Points

If you are interested, you can check how I implemented my solution with next/previous buttons - https://github.com/SergeyPodgornyy/treehouse-projects/tree/master/jquery/3_-_Image_gallery

Sergey,

I tried to implement your code into my project, after some minimal modifications. But it does't seem to be working for me. Could you take a quick look? Need you help. Thnx.

Tracy Excell
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Tracy Excell
Front End Web Development Techdegree Graduate 15,333 Points

Hello, Sergeny. I am trying to do this task at the moment and your code is making the most sense to me currently. I am trying to get my head around the steps needed to make these buttons, would you please explain them to me? Why do we need to go to the parent element? Why can the code not be something like....

$(buttonNext).click(function()){ thisImage.next().append(overlay); )};

Thank you, if you can help me understand it, it would be appreciated.

Andrew Shook
Andrew Shook
31,709 Points

Ashley, could you please post all the html and javascript code for the light box please. It will make it easier to trouble shot if we can see all of your code.

ana s
ana s
1,574 Points

Hello Mods -

I'd like to know the answer to adding the "NEXT" button to the image gallery as well. Not grasping this yet .. I imagine you would have to look at the next img src and use next() but I am lost as to how to retrieve that and cycle through. Do we need to run a loop here?

Ashley Livingston
Ashley Livingston
6,931 Points

Okay so this was how I did it. There may be a better way, but this is working for me.

first, I added previous and next buttons directly into my html, after the gallery

<div class = "arrows">
        <div class = "previous">
            Previous
        </div>

        <div class = "next">
            Next
        </div>
</div>

Then I styled them how in CSS, and was sure to add "display: none" to my arrows class so they were hidden

Now here's my full jquery - I commented everything line by line to explain what I did

var $overlay = $('<div id="overlay"></div>');
var $image = $('<img id = "overlayImg"></img>');
var $nextImage = $("<img>");

$("body").append($overlay);  //adds the overlay to your body
$("body").append($image);   //adds the empty overlay image container to your body

$(".galleryimage").click(function(){  //triggers when you click on one of your gallery images
    event.preventDefault(); //prevent link from opening in new window
    $overlay.show(); //show the overlay over your body
    $('.arrows').show();  //show your previous and next buttons 
    getCurrentImage(this);   //call the function that captures information about the image container you clicked on
    $image.show();  //show the image you clicked on
});


$('.next').click(function(event) {  //triggers when you click on your next button
    getNextImage();  //call the function that captures information about the next image inline to be shown
    $image.show();  //shows the next image 
});

function getCurrentImage (currentImage) {  //receive the image container that was clicked on
    thisImage = $(currentImage).children();    //identify the child of the image container i.e. the image itself 
    thisImageLocation = $(thisImage).attr("href");  //capture the href/src information of the image that was clicked
    $image.attr("src", thisImageLocation);    //update your overlay image info to reflect the image that was clicked
}


function getNextImage() {
    nextImageParent = $(thisImage).parent().next();  //get the image container of the next image
    nextImage = $(nextImageParent).children();  //identify the child of the next image container i.e. the second (then 3rd, 4th, etc.) image 
    nextImageLocation = $(nextImage).attr("href");   //capture the href/src information of the second image
    $image.attr("src", nextImageLocation);    //update your overlay image info to reflect the next image
    getCurrentImage(nextImageParent);  //call the function that captures information about your new current image
}


$overlay.click(function(){ //hides the overlay and image when you click out
    $overlay.hide();
    $image.hide();
    $image.attr("src", "");
    $('.arrows').hide();
});

I didn't add the functionality for my previous button yet, but it's basically just the opposite of what I did for next.

Gabriel Ward
Gabriel Ward
20,222 Points

Thank you Ashley,

I'll use this as a model to try and get it to work for me. The biggest difference is that I'm including a next button by using pseudo classes in CSS, insted of inserting using HTML. Hopefully it doesn't change thigns too much. If I can't get that to work then I'll try your exact method. Did you work this out on your own? This is impressive!

Ashley Livingston
Ashley Livingston
6,931 Points

As long as you have a previous/next class you can reference in your jquery it should be fine. You won't show and hide them the same way, that's all. Also just for clarity's sake, my gallery images are set up like below. If your individual gallery images aren't within a containing div, my code won't work for you.

<div class = "galleryimage">
    <a href = "img/largeimg1.min.jpg"><img src = "img/img1.jpg" width= "100%"></a>
</div>

<div class = "galleryimage">
    <a href = "img/largeimg2.min.jpg"><img src = "img/img2.jpg" width= "100%"></a>
</div>

<div class = "galleryimage">
    <a href = "img/largeimg3.min.jpg"><img src = "img/img3.jpg" width= "100%"></a>
</div>
Gabriel Ward
Gabriel Ward
20,222 Points

Cool ok, I'll post my code here so you can see it,

<div class="grid-container imageGallery">
        <div class="grid-3">
            <a href="img/item-01.png">
                <div class='image'>
                    <img class="feat-img" src="img/item-01.png" alt='Image by Bob'/>
                    <div class='text'></div>
                </div>
            </a>
            <!-- <p class='caption'>Caption</p> -->
        </div>
        <div class="grid-3">
            <a href="img/item-02.png"><div class='image'>
                <img class="feat-img" src="img/item-02.png" alt='Image by Jim'/>
                    <div class='text'></div>
            </div></a>
            <p class='caption'>Caption</p>
        </div>
        <div class="grid-3">
            <a href="img/item-03.png"><div class='image'>
                <img class="feat-img" src="img/item-03.png" alt='Image by Johnny'/>
                    <div class='text'></div>
            </div></a>
            <p class='caption'>Caption</p>
        </div>
        <div class="grid-3">
            <a href="img/item-04.png"><div class='image'>
                <img class="feat-img" src="img/item-04.png" alt='Image by Dave'/>
                    <div class='text'></div>
            </div></a>
            <p class='caption'>Caption</p>
        </div>
    </div>

This is my jQuery without any changes yet

$(document).ready(function(){
//Problem: When user clicks on an image they are taken to a dead end.
//Solution: Create an overlay with the image centered on it - Lightbox

    var $lightbox = $('<div class ="lightbox"></div>');
    var $lightboxImage = $('<img>');
    var $nextLightboxImage = $('<img>');
    var $button = $('<div id="nav-icon1"><span></span><span></span><span></span></div>');
    var $caption = $('<p></p>');



    //Add an image to overlay
    $lightbox.append($lightboxImage);
    //Add a caption to the overlay
    $lightbox.append($caption);
    //Add a button to the lightbox
    $lightbox.append($button);
    //Add overlay
    $('body').append($lightbox);
    //Capture the click event on a link to an image
    $('.imageGallery a').click(function(event){
        event.preventDefault();
        var imageLocation = $(this).attr('href');
        // Update the overlay with the image that is clicked,
        $lightboxImage.attr('src', imageLocation);
        // Show the overlay.
        $lightbox.show();



        //1.3 Get the image alt attribute and set caption.
        var captionText = $(this).find('img').attr('alt');
        $caption.text(captionText);
    });
    //Append next image in gallery and detach current one when button is clicked on
    $button.click(function(){
        var nextImageLocation = $(this).next.attr('href');
        $nextLightboxImage.attr('src', nextImageLocation);
        $lightbox.detach($lightboxImage);
        $lightbox.append($nextLightboxImage);
    });
    //When the overlay is clicked
        //Hide the overlay.
    $lightbox.click(function(){
        $lightbox.hide();
    });
});
Ashley Livingston
Ashley Livingston
6,931 Points

Right, that's the jquery I posted originally when I first tried, I think. The reason it doesn't work is because where you have

$button.click(function(){
        var nextImageLocation = $(this).next.attr('href');
        $nextLightboxImage.attr('src', nextImageLocation);
        $lightbox.detach($lightboxImage);
        $lightbox.append($nextLightboxImage);
    });

The "this" it is referring to is actually the next button that gets clicked. The next item after your "next button" in the DOM isn't your next gallery item. It's probably not anything at all, depending on how you've set it up.

Also, you need to jump not just to the next item, but to the image inside your next containing div, which is why in my new code for the next button click, I move up to the parent element of the current image, and then to the next element (your second gallery containing div), and then to its child, which your next image.

And the reason I used functions is because you need the data for the current image to be continuously updated every time you hit the next button. Otherwise, the next button will only work once, and you won't be able to move passed your second image!

I hope that makes sense lol

Gabriel Ward
Gabriel Ward
20,222 Points

That's impressive. How'd you go about solving it? Did it take you long?

My HTML is set up differently from yours. Do you think that changes much? The biggest difference being that the images are within more containing divs.

Ashley Livingston
Ashley Livingston
6,931 Points

I don't think your configuration should matter in regard to this jquery code, cause your href, which is the value we're seeking, is a child of your grid div, not your image div. So just replace my $('.galleryImage') with your $('.grid-3').

It didn't take me long - I first posted this thread several months ago, and I've come a long way since then. I never bothered to figure it back then but when I saw your post I decided to give it a whirl.

Gabriel Ward
Gabriel Ward
20,222 Points

Wow cool ok. What steps have you taken to come a long way? I've improved as well. I've been learning for about 5 months but always keen to hear how others are doing it.

Ashley Livingston
Ashley Livingston
6,931 Points

Pretty much just trial and error haha. I'll watch the videos here and once I think I have the faintest idea of how something works I'll just starting building something. If I hit a snag, I'll use google to find a solution. I learned jQuery (and basic PHP and SQL) by building a drag and drop style task organizer for the web. What's your method?

Gabriel Ward
Gabriel Ward
20,222 Points

Cool I guess, by trial and error, and building things. I've built a Wordpress theme from scratch which was a big learning curve. I try to watch videos on here. But I find that things only really sink for me when I'm trying to build something. Like this simple lightbox. The basics of it are straightforward. Adding this next button is a step up. I post questions on here.

Do you mind if I post my updated code? Now I've got the lightbox showing but nothing is appended to it.

$(document).ready(function(){
//Problem: When user clicks on an image they are taken to a dead end.
//Solution: Create an overlay with the image centered on it - Lightbox

    var $lightbox = $('<div class ="lightbox"></div>');
    var $lightboxImage = $('<img>');
    var $nextLightboxImage = $('<img>');
    var $button = $('<div id="nav-icon1"><span></span><span></span><span></span></div>');
    var $caption = $('<p></p>');

$("body").append($lightbox);  //adds the overlay to your body
$("body").append($lightboxImage);   //adds the empty overlay image container to your body

$(".imageGallery a").click(function(){  //triggers when you click on one of your gallery images
    event.preventDefault(); //prevent link from opening in new window
    $lightbox.show(); //show the overlay over your body
    $button.show();  //show your previous and next buttons 
    getCurrentImage(this);   //call the function that captures information about the image container you clicked on
    $lightboxImage.show();  //show the image you clicked on
});


$button.click(function(event) {  //triggers when you click on your next button
    getNextImage();  //call the function that captures information about the next image inline to be shown
    $image.show();  //shows the next image 
});

function getCurrentImage (currentImage) {  //receive the image container that was clicked on
    thisImage = $(currentImage).children();    //identify the child of the image container i.e. the image itself 
    thisImageLocation = $(thisImage).attr("href");  //capture the href/src information of the image that was clicked
    $lightboxImage.attr("src", thisImageLocation);    //update your overlay image info to reflect the image that was clicked
}


function getNextImage() {
    nextImageParent = $(thisImage).parent().next();  //get the image container of the next image
    nextImage = $(nextImageParent).children();  //identify the child of the next image container i.e. the second (then 3rd, 4th, etc.) image 
    nextImageLocation = $(nextImage).attr("href");   //capture the href/src information of the second image
    $lightboxImage.attr("src", nextImageLocation);    //update your overlay image info to reflect the next image
    getCurrentImage(nextImageParent);  //call the function that captures information about your new current image
}


$lightbox.click(function(){ //hides the overlay and image when you click out
    $lightbox.hide();
    $lightboxImage.hide();
    $lightboxImage.attr("src", "");
    $button.hide();
});
});
Ashley Livingston
Ashley Livingston
6,931 Points

Did you change your grid-3 in your html to imageGallery?

$(".imageGallery a").click(function(){  //triggers when you click on one of your gallery images
    event.preventDefault(); //prevent link from opening in new window
    $lightbox.show(); //show the overlay over your body
    $button.show();  //show your previous and next buttons 
    getCurrentImage(this);   //call the function that captures information about the image container you clicked on
    $lightboxImage.show();  //show the image you clicked on
});

Take the "a" out of that first line. We want to call the top most containing div for my exact code to work. Let me know if that works!

Gabriel Ward
Gabriel Ward
20,222 Points

I have to keep the grid 3 for styling. I just updated my HTML to look like the following and took out the 'a'. Still no luck. A blank lightbox!

<div class="grid-3 imageGallery">
            <a href="img/item-01.png">
                <div class='image'>
                    <img class="feat-img" src="img/item-01.png" alt='Image by Bob'/>
                    <div class='text'></div>
                </div>
            </a>
            <p class='caption'>Caption</p>
        </div>
        <div class="grid-3 imageGallery">
            <a href="img/item-02.png"><div class='image'>
                <img class="feat-img" src="img/item-02.png" alt='Image by Jim'/>
                    <div class='text'></div>
            </div></a>
            <p class='caption'>Caption</p>
        </div>
        <div class="grid-3 imageGallery">
            <a href="img/item-03.png"><div class='image'>
                <img class="feat-img" src="img/item-03.png" alt='Image by Johnny'/>
                    <div class='text'></div>
            </div></a>
            <p class='caption'>Caption</p>
        </div>
        <div class="grid-3 imageGallery">
            <a href="img/item-04.png"><div class='image'>
                <img class="feat-img" src="img/item-04.png" alt='Image by Dave'/>
                    <div class='text'></div>
            </div></a>
            <p class='caption'>Caption</p>
        </div>
Gabriel Ward
Gabriel Ward
20,222 Points

I managed to append the button and image by using:

$lightbox.append($lightboxImage);   //adds the empty overlay image container to your body
$lightbox.append($button);

But still no luck on the button functionality haha. I'm not sure.

How long have you been learning coding for?

Ashley Livingston
Ashley Livingston
6,931 Points

Okay, I think I got it...

I copied and pasted your code into my workspace and added some rudimentary css for the overlay. I think what you're missing is this:

   var $lightboxImage = $('<img id = "overlayImg"></img>');

you had only declared a blank img in your lightboximage... you need to give it an id, and then a style to render it correctly in your CSS. When I added that your code in my own workspace, it displayed correctly. You have to give it a high z-index.

EDIT: and yes, you will need to append your button to the body, or wherever if you didn't include them in your HTML already - forgot that!

Gabriel Ward
Gabriel Ward
20,222 Points

Ok, this is using your button method? Also, I'm still not sure why your $('.body').append($lightboxImage) isn't working for me.

Ashley Livingston
Ashley Livingston
6,931 Points

No, I just used the code you had provided to see if I could render an image in the lightbox. Once I added the line from my last comment to give your lightboxImage an id and then a style, it worked perfectly.

Gabriel Ward
Gabriel Ward
20,222 Points

Ok thanks for your help Ashley. I really appreciate it. I'm going to have to scrap my pseudo class button I think. If I use the append method I originally used on the button and image it's fine, but there's no button functionality. I just tried your append mehtod and adding the id to the image and no luck. I can't work out what I'm doing wrong. Perhaps I should choose something else to study, I don't know. Are you a professional developer now?

Ashley Livingston
Ashley Livingston
6,931 Points

No way - you will get it, I'm sure it's a really small thing. send me an email ashleyhlivingston @ gmail dot com if you want with your css/html/js files and I'll try and work through it.

In the mean time, try inserting your prev/next buttons directly into your HTML like I did, and using my jquery just to see if it works. Once you get it working, it's much easier to make changes and add functionality so it works the way you want.

I'm doing freelance web design at the moment, and my goal is to be a software developer. I'm hoping that will be a reality in about 9-12 months from now.

Ashley Livingston
Ashley Livingston
6,931 Points

This jquery - which is yours (I copied and pasted) and made only slight modifications works 100% for me so it should work for you too.

$(document).ready(function(){
//Problem: When user clicks on an image they are taken to a dead end.
//Solution: Create an overlay with the image centered on it - Lightbox

    var $lightbox = $('<div class ="lightbox"></div>');
    var $lightboxImage = $('<img id = "overlayImg"></img>>');
    var $nextLightboxImage = $('<img>');
    var $button = $('<div id="nav-icon1">Next</div>');
    var $caption = $('<p></p>');

$("body").append($lightbox);  //adds the overlay to your body
$("body").append($lightboxImage); 
$("body").append($button);   //adds the empty overlay image container to your body

$(".imageGallery").click(function(){  //triggers when you click on one of your gallery images
    event.preventDefault(); //prevent link from opening in new window
    $lightbox.show(); //show the overlay over your body
    $button.show();  //show your previous and next buttons 
    getCurrentImage(this);   //call the function that captures information about the image container you clicked on
    $lightboxImage.show();  //show the image you clicked on
});


$button.click(function(event) {  //triggers when you click on your next button
    getNextImage();  //call the function that captures information about the next image inline to be shown
    $image.show();  //shows the next image 
});

function getCurrentImage (currentImage) {  //receive the image container that was clicked on
    thisImage = $(currentImage).children("a");    //identify the child of the image container i.e. the image itself 
    thisImageLocation = $(thisImage).attr("href");  //capture the href/src information of the image that was clicked
    $lightboxImage.attr("src", thisImageLocation);    //update your overlay image info to reflect the image that was clicked
}


function getNextImage() {
    nextImageParent = $(thisImage).parent().next();  //get the image container of the next image
    nextImage = $(nextImageParent).children("a");  //identify the child of the next image container i.e. the second (then 3rd, 4th, etc.) image 
    nextImageLocation = $(nextImage).attr("href");   //capture the href/src information of the second image
    $lightboxImage.attr("src", nextImageLocation);    //update your overlay image info to reflect the next image
    getCurrentImage(nextImageParent);  //call the function that captures information about your new current image
}


$lightbox.click(function(){ //hides the overlay and image when you click out
    $lightbox.hide();
    $lightboxImage.hide();
    $lightboxImage.attr("src", "");
    $button.hide();
});
});

I also used these styles:

.lightBox{
      background:rgba(0,0,0,0.8);
      width:100%;
      height:100%;
      position:fixed;
      top:0;
      left:0;
      display:none;
      z-index: 0;
    }

#overlayImg {
        position: absolute;
        display: none;
        top: 12%;
        /*width: 35%;*/
        max-width: 35%;
        max-height: 75%;
        /*margin-left: 32.5%;
        margin-right: 32.5%;*/
        margin: 0 auto;
        left: 0;
        right: 0;
        border: 4px solid black;
        z-index: 10;
    }

    #overlay a {
        color: white;
        margin-left: 45%;
    }

    #nav-icon1 {
        color: grey;
        position: fixed;
        top: 200px;
        left: 75%;
        display: none;
    }
Gabriel Ward
Gabriel Ward
20,222 Points

Thank you Ahsley. Yea sometimes I get hard on myself as to how good I am at this stuff because I often take ages to work something out. I always do figure it out eventually though. The old self-doubt!

I'll have a go now with inserting the button straight into the HTML

Gabriel Ward
Gabriel Ward
20,222 Points

Wow cool so that works. I really want to work out where I've been going wrong haha.

Ashley Livingston
Ashley Livingston
6,931 Points

Awesome! I'm glad you got it working - now you can play with it and see things do or don't work. I find that the console is a great help with debugging. I use it all the time!

Gabriel Ward
Gabriel Ward
20,222 Points

I'm looking forward to working it out. Thanks for your time and patience Ashley!

What I'm confused about is that you're using the variable thisImage in the getNextImage function even tough thisImage is from a previous function. Doesn't variable scope limit that variable to the first function only?