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 jQuery Basics (2014) Creating a Simple Lightbox Perform: Part 3

Ray Mak
Ray Mak
4,667 Points

Stop the image from hiding if clicked on image and caption?

Hello,

I was watching jQuery Basics tutorial of creating simple image gallery. I created my own simple gallery with overlay div. In the video, it says, when clicked on overlay, the image or you can say the whole DIV will hide. It works great per the video tutorial, but I don't want to hide the image when clicked on the image and caption.

Here is my JSFiddler: http://jsfiddle.net/rahilmaknojia/wtkrau0j/

4 Answers

Rui Bi
Rui Bi
29,853 Points

No, if you attach the click event to the body, then the gallery would not work.

The reason is because everything is a child of the body. So when you click anywhere, you will trigger that click event and hide the overlay. So when you click the image, both the event handlers to show and hide the overlay are triggered, and the end result is that you will not see the overlay.

What you can do is to make a transparent invisible div that spans the entire overlay. Then you next the image and caption within another div, so the html structure would be like this:

<div class="overlay">
    <div class="background">
    </div>
    <div class="content">
        <img>
        <p></p>
    </div>
</div>

So the way you want to append to the DOM is (after you setup the variables):

$content.append($img).append($caption); $overlay.append($background).append($content);

Then the event handler to close would be:

$background.click(function(){ $overlay.hide() });

You need the overlay, and the content to be relatively positioned and the background to be absolutely positioned, with the content having a higher z-index than the background.

You can position and size the content however you want, and style the background however you want.

Rui Bi
Rui Bi
29,853 Points

Another approach would be use jQuery to stop event propagation by attaching a click event to child elements and call stopPropagation().

For example,

$(child).click(function(evt){ evt.stopPropagation(); });

which prevents the click from bubbling to the parent.

Basically that says: if the child is clicked on, then do not activate any click events on any of its parents/ancestors.

With larger more complex applications, you would probably want to use the jQuery/event propagation approach rather than manipulating your CSS.

Here is your original JS Fiddle, but with event propagation being used to prevent the overlay from closing when the caption or image is closed:

JS Fiddle with stopPropagation

Ray Mak
Ray Mak
4,667 Points

I like the approach of using stopPropagation and was looking for jQuery method to fix my original problem. Before I started this post, I was actually using stop() method to make it work, but I guess that wasn't enough and couldn't work in this scenario because that is mostly use for stopping the animation.

Again, you taught two ways of fixing my problem :)

I really appreciate your help on providing me detailed explaination on both scenarios.

Rui Bi
Rui Bi
29,853 Points

They way to do that would be to make the overlay a sibling of the images and captions instead of the parent, and would involve some absolute positioning. Then, when you click on the image or captions, you will not trigger the click event for hiding the div.

The HTML structure would look something like this (you don't need to include this html on your actual html file, but writing it out a html template prior to coding in the jQuery can make it a bit easier):

<div class="lightbox">
<div class="overlay">
</div>
<img>
<p>Caption text...</p>
</div>

You would also need to set up the CSS to position the overlay, image, and caption texts correctly. You would add the following CSS to your positioning logic.

.lightbox{
display: none;
position: relative;
}

.overlay{
position: absolute;
z-index: 0;
left: 0;
top: 0;
width: 100%;
height: 100%;
}

.lightbox img, .lightbox p{
position: relative;
z-index: 100;
//other positioning code for magins, centering, etc goes here
}

Then the jQuery would be:

$(document).ready(function(){ var $lightbox = $('<div class="lightbox"></div>'); var $overlay = $('<div class="overlay"></div>'); var $img = $('<img'>); var $caption = $('<p></p>');

//Sets up your lightbox $lightbox.append($overlay).append($img).append($caption);

//Adds to body $('body').append($lightbox);

//Shows lightbox $("#imageGallery a").click(function(event){ event.preventDefault(); var imageLocation = $(this).attr("href");

//Update overlay with the image linked in the link $img.attr("src", imageLocation);

//Get child's alt attribute and set caption var captionText = $(this).children("img").attr("alt"); $caption.text(captionText);

//Show the lightbox $lightbox.show(); });

//Hides lightbox when overlay is clicked $overlay.click(function(event){ $lightbox.hide(); });

});

EDIT: How do you I use Markdown for JS?

Rui Bi
Rui Bi
29,853 Points

Here is the JSFiddle, updated so that the overlay is not hidden when the images or captions are clicked. I worked off your JSFiddle file, so it looks a little different than the code I have above.

Updated JS Fiddle

Rui Bi
Rui Bi
29,853 Points

With your 50% screen size overlay, you just need to add this code after the event handler on the body:

$overlay.click(function(evt) { evt.stopPropagation(); }

note: evt is a parameter name for the event, you can name it anything. evt is the common convention, but event, or just e are common too.

Stopping event propagation is a very common jQuery pattern, but I don't think its covered in any of the Javascript courses on TreeHouse unfortunately.

Ray Mak
Ray Mak
4,667 Points

Hi Rui,

Thanks for your suggestion and it works every well in my project. What if I shrink the size of the Overlay div such as 50% and when I click outside 50% of OverLay div, it will go back to body element and hide the div?

For example like this: $("body").click(function() { $overlay.hide(); });