Enlarge img on click, click again to minimize - javascript

I'm making a website which requires pictures to be clickable. If you click on the image it should enlarge and show in the middle of the screen. If you then click again it should go smaller again and back on its place.
$(document).ready(function() {
$("#header").load("header.html .header");
$("#footer").load("footer.html .footer");
$("body").on('click', function(){
if(!$(".img1, .img2").hasClass('enlarged')){
$(".img1, .img2").on('click',function(){
$(this).addClass('enlarged');
});
}else{
$("body").on('click', '.enlarged', function(){
$(this).removeClass('enlarged');
});
}
});
});
.enlarged{
position:absolute;
z-index:2;
width:500px;
height:600px;
top:-10%;
left:300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container" class="container">
<aside class="aside"><img src="fotos/foto1.JPG" id="img1" class="img1" style="transform:rotate(90deg);"/><img src="fotos/foto2.JPG" class="img2" style="transform:rotate(90deg);"/></aside>
<div class="box"></div>
</div>
My current script works but is very wonky. It only enlarges once and you have to triple-click.
I already made a question about it before, but after I updated nobody answered.
Also I'm not sure how to add images on Stack Overflow, otherwise I would've made a snippet.

Your click handler isn't actually performing the logic you want, it's just assigning other click handlers. Then upon further clicks those are performing the logic you want (sort of), but also further assigning more click handlers. After a couple clicks, this is going to get entirely weird.
You just want one click handler for your target elements:
$("body").on('click', '.img1, .img2', function(){
});
This handler would be invoked for any .img1 or .img2 on the page. Inside this handler, conduct your logic:
if (!$(this).hasClass('enlarged')) {
$(this).addClass('enlarged');
} else {
$(this).removeClass('enlarged');
}
Or, even simpler:
$(this).toggleClass('enlarged');

A lot of things are happening in your code:
You first only add a click handler on the body element. Which means the 1st time you click on the body it enters your conditional. In your first if you add another click handler, but now on .img1, .img2. The opposite (removing the enlarged class) is again on the body element and not on the .img1, .img2 elements.
Some advice:
Use only 1 class to toggle the enlarged state
Personally I'm a big fan of BEM, maybe not relevant for now.
Split up your JS concerns; I would create a plugin for this behaviour
A bit of code to point you in the right direction:
var $elements = $('.enlarge-img');
// in this case not very relevant, but a good habit to have
// a method to instantiate
function initialize() {
addEventListeners();
}
// adding event listeners
function addEventListeners() {
$elements.on('click.namespace', handleClick);
$('body').click('click.namespace', handleClickBody);
}
// You might want to handle clicks on the <body> to remove
// the enlarged state of any image
function handleClickBody(event) {
$elements.removeClass('enlarge-img--enlarged');
}
// If you click an image, you want to toggle the enlarged state class
function handleClick(event) {
event.preventDefault(); // not necessary on a <img/> but needed if you use a link
$(event.target).toggleClass('enlarge-img--enlarged`);
}
initialize();
Hopefully this helps you in the right direction of creating re-usable code. Happy coding!

Related

Jquery mouseover and mouseleave

I have one problem about mouseover and mouseleave function.
In this DEMO page you can see there is a picture. When you hover over muse then you can see the hovercard. The hovercard inside have click to follow link. But you can not click that link because when you mouseleave on that link the hovercard to be closed. How can I solve this problem. Is anyone can help me ?
The Jquery code is here:
$(document).ready(function(){
function showProfileTooltip(e, id){
e.append($('.p-tooltip').css({
'top':'20',
'left':'80'
}).show());
//send id & get info from go_card.php
$.ajax({
url: 'go_card.php?uid='+id,
beforeSend: function(){
$('.p-tooltip').html('Yükleniyor..');
},
success: function(html){
$('.p-tooltip').html(html);
}
});
}
function hideProfileTooltip(){
$('.p-tooltip').hide();
}
$('.summary a').mouseover(function(e){
var id = $(this).attr('data-id');
showProfileTooltip($(this), id);
});
$('.summary').mouseleave(function(){
hideProfileTooltip();
});
});
and HTML code:
<div class="paylasilan-alani">
<div class="paylasan-profil-fotosu profile">
<div class="summary" id="summary1" data-id="7"><img src="http://www.designbolts.com/wp-content/uploads/2013/11/Frozen-Movie-poster-payoff-Wallpaper-HD1.jpg" width="64" height="64"/></div>
</div>
<div class="paylasilan">Some text here.</div>
</div>
The issue is the .mouseover() function which is triggering the ajax call over and over.
per the documentation for .mouseover():
This event type can cause many headaches due to event bubbling. For instance, when the mouse pointer moves over the Inner element in this example, a mouseover event will be sent to that, then trickle up to Outer. This can trigger our bound mouseover handler at inopportune times. See the discussion for .mouseenter() for a useful alternative.
instead switch to .hover(). You can use a callback to handle the mouseleave() functionality too:
$('.summary a').hover(function(e){
var id = $(this).attr('data-id');
showProfileTooltip($(this), id);
}, function(){
hideProfileTooltip();
});
Also the plugin you are using which is adding inline styles to .summary and the class scroll-to-fixed-fixed is setting .summary to z-index:0. The z-index property is inherited by it's children and this is causing your pop up to sit behind other elements. I would either look through the plugin's JS file and remove this or override it in your CSS by adding:
.summary{
z-index: 1 !important;
}
JSBIN
function hideProfileTooltip(){
$('.p-tooltip').hide();
}
$('.summary a').mouseover(function(e){
var id = $(this).attr('data-id');
showProfileTooltip($(this), id);
});
$('.summary').mouseleave(function(){
hideProfileTooltip();
});
This is your issue code. To achieve your purpose. The key is the.p-tooltip doesn't disapper when trigger the function ummary.mouseleave if your cursor move to the .p-tooltip,but when your cursor move to other place. The .p-tooltip should be disappear.
So I create a JSBIN to simulate your issue. The jsbin simply simulates your problem. It's just a way with a HTML structure to fixed your issue. I believe there is another way to resolve it. But use this structure is a brief way to make it. So, I advise you should repaint your HTML, specially pay more attention the parent & child relation.
That's all.
You need to specify the mouseleave function inside the mouse enter function. This way, after focusing on the element, it hides if the user leaves the element.

Strange lag which disappears by clicking anywhere on the html body

I have some overlay elements which are display: none initially but turn to display: inline when I hover over specific items on the page, and disappear again when the mouse hovers over something else. Exactly same behavior as tool-tips with the difference that this overlay objects have clickable and interactive elements (such as a jquery accordion).
Everything works perfectly, until I interact with these overlay elements, i.e. click on one of the clickable items in the overlay element. Then, once that overlay item becomes display:none again, the page becomes extremely laggy in terms of how long it takes when I hover over an item to find its corresponding overlay element (they are selected by their id) and for it to appear and disappear.
The strange thing is that if I click anywhere on the html body, the lag disappears and everything becomes fast as in the beginning.
Out of despair, I have tried to programmatically call blur, focus, trigger('click') once the overlay element is set back to display:none but none has helped so far, and I have to manually click on the page for the lag to go away.
Any idea what causes such behavior and how I can fix it? thanks,
Edit: code
CSS part:
span.overlay {
z-index:10;
display:none;
position:absolute;
}
span.visible { display:inline; }
HTML part: lots of such span elements, each with their own unique id.
<span class='overlay ui-widget-content' id='xyz'>
<!-- lots of stuff here -->
</span>
javascript part:
/* displays overlay element when user hovers over the first td */
$('table.foo > tbody > tr > td:first-child').hover(
function(e) {
$(this).parent().tooltip('disable');
var elem = $('#' + $(this).parent().data('overlay-id'));
if (!elem.hasClass('visible')) {
elem.css('left', e.pageX + 20).css('top', e.pageY).addClass('visible');
elem.find('.accordion:first').accordion('refresh');
}
}, function() {
var elem = $('#' + $(this).parent().data('overlay-id'));
if (! elem.is(':hover') && ! elem.hasClass('pin')) {
$(elem).removeClass('visible');
}
$(this).parent().tooltip('enable');
});
/* if mouse leaves span.visible and it is not pinned it will hide the span */
$('body').on('mouseleave', 'span.visible',
function() {
if (!$(this).hasClass('pin')) {
$(this).removeClass('visible');
}
});
Edit: profiling the code, it seems that get offsetHeight and get offsetWidth take way longer than before. Yet I do not know why this should happen and why it should go away by clicking on the page.
previously, when I do not observe the problem, these two functions each take less than 3%.
try binding the mouseleave event upon opening the "tooltip". Replace your code with this (not tested):
/* displays overlay element when user hovers over the first td */
$('table.foo > tbody > tr > td:first-child').on('mouseenter',
function(e) {
$(this).parent().tooltip('disable');
var elem = $('#' + $(this).parent().data('overlay-id'));
if (!elem.hasClass('visible')) {
elem.css('left', e.pageX + 20).css('top', e.pageY).addClass('visible');
elem.find('.accordion:first').accordion('refresh');
// notice the "ONE" handler, it'll unbind the event after execution
elem.one('mouseleave', function() {
if (!$(this).hasClass('pin')) {
$(this).removeClass('visible');
}
$(this).parent().tooltip('enable');
});
}
}
);
Notice the one listener to unbind the event after it's first execution.
I can't guarantee that this will fix your issue but I experienced lots of performance hits when a page has A LOT of elements and browsers need to check hover events that change very quickly.
This way the browser only needs to check one mouseleave event. And if it happened, it's gone again. It seems you may have too many bound events and don't clean them up properly.
I'm not sure if I replicated your desired functionality correctly so please add code if I missed something. I was unsure why exactly you'd need to bind a mouseleave event via body AND via .hover().

change div class onclick on another div, and change back on body click

Let me define the problem a little bit more:
i have
<div class="contact">
<div id="form"></div>
<div id="icon"></div>
</div>
i want onclick on #icon, to change the class of .contact to .contactexpand( or just append it).
Then i want that the on body click to change the class back, but of course that shouldnt happen when clicking on the new class .contactexpand, and if possible that clicking on icon again changes the class back again.
I tried numerous examples and combinations but just couldn't get the right result and behavior.
Check this: Working example
Let's go step by step
I want onclick on #icon, to change the class of .contact to .contactexpand( or just append it). […] and if possible that clicking on icon again changes the class back again.
You want to use the toggleClass() method to achieve this. Simply:
$('#icon').on('click', function(e){
$(this).parent()
.toggleClass('contact')
.toggleClass('contactexpand');
});
Then i want that the on body click to change the class back
You will have to make sure that body removes contactexpand class and adds contact. At this point I would just give the container element an id (or class if you prefer), just to make things simpler. Then what you do is pretty simple:
$('body').on('click', function(e){
$('#thisdiv')
.removeClass('contactexpand')
.addClass('contact');
});
but of course that shouldnt happen when clicking on the new class .contactexpand.
This is the step that the other answers missed, I think. Since everywhere you click, you also click on the body element, you will always trigger the click event on the body, hence removing the contactexpand class and adding the contact one.
Enter event.stopPropagation(). This method will make sure that the events doesn't bubble up the DOM, and will not trigger the body click.
$('#thisdiv').on('click', function(e){
e.stopPropagation();
});
Working example
You can add a class to parent element like the following code.
$(".contact #icon").click(function(){
var element = $(this).parent(".contact");
element.removeClass("contact").addClass("contactexpand");
});
I like to the jQuerys toggleClass function like so:
$('#icon').click(function(){
$('#contactbox').toggleClass('contact');
$('#contactbox').toggleClass('contactexpand');
});
Or you could use addClass('className') and removerClass('className') if you would like to apend it rather than toggle it :)
Here is an example: http://jsfiddle.net/aUUkL/
You can also add an onclick event to the body of the page and use hasClass('className') to see whether or not to toggle the class when the body is clicked. You could use something like this (Although I havent tested this bit!):
$('body').click(function(){
if( $('#contactbox').hasClass('contactexpand') ){
$('#contactbox').addClass('contact');
$('#contactbox').removeClass('contactexpand');
}
});
You can do this
$('body').on('click', function(event) {
if ($(event.target).attr('id') == 'icon') {
$(event.target).parent().toggleClass('contactexpand');
} else {
$('.contact').removeClass('contactexpand');
}
});
Check out this jsfiddle
var $contact = $('.contact');
$contact.find('#icon').click(function(e, hide) {
e.stopPropagation();
$contact[hide ? 'removeClass' : 'toggleClass']('contactexpand');
});
$(document).on('click', function(e) {
if (e.srcElement === $contact[0]) return;
$contact.find('#icon').trigger('click', true);
});
http://jsfiddle.net/kZkuH/2/

Jquery - Prevent click event from being triggered through an overlying layer

.PopBgd is 100% of the screens size with another div .PopUp contained within .PopBgd and appearing on top of it.
Clicking on .PopBgd gives the desired effect of Hiding. However clicking anywhere in PopUp also runs the fadeOut part of the script below.
QUESTION
How to prevent the fadeOut part of the script from triggering though overlying divs?
$('.BtnPop').click(function(e) {
e.preventDefault();
$($(this).data('popup')).fadeIn();
$('.PopClose, .PopBgd').click(function() {
$('.PopBgd').fadeOut();});
});
ANSWER
<button type="button" class="BtnPop" data-popup=".Pop1">CLICK</button>
<div class="Pop1 PopBgd">
<div class="PopUp">
<a class="PopClose">×</a>
<div>Content</div>
</div>
</div>
$('.BtnPop').click(function(e) {
e.preventDefault();
$($(this).data('popup')).fadeIn();
});
$('.PopClose, .PopBgd').click(function() {
$('.PopBgd').fadeOut();});
$('.PopUp').click(function(e) {
e.stopPropagation();
});
NEW QUESTION
How to use StopPropogation when the target div's name is unknown?
What I have tried above does not work.
I resolved my additional problem by simply adding a second class name that was static to the desired div to allow stopPropogation to work as normal.
$('.Pop').click(function(e) {
e.stopPropagation();
});
.stopPropagation() "Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event."

Do I have to duplicate this function? - jQuery

I'm using this function to create an transparent overlay of information over the current div for a web-based mobile app.
Background: using jQTouch, so I have separate divs, not individual pages loading new.
$(document).ready(function() {
$('.infoBtn').click(function() {
$('#overlay').toggleFade(400);
return false;
});
});
Understanding that JS will run sequentially when i click the button on the first div the function works fine. When I go to the next div if I click the same button nothing "happens" when this div is displayed, but if i go back to the first div it has actually triggered it on this page.
So I logically duplicated the function and changed the CSS selector names and it works for both.
But do I have to do this for each use? Is there a way to use the same selectors, but load the different content in each variation?
Would something like this work? I'm assuming what you want is for different buttons to call toggleFade on different overlay divs.
function makeOverlayHandler(selector) {
return function() {
$(selector).toggleFade(400);
return false;
}
}
$('button selector').click(makeOverlayHandler('#overlay1'));
$('another button selector').click(makeOverlayHandler('#overlay2'));
You could also change makeOverlayHandler's selector parameter to a jQuery object instead of a selector and call it like this: makeOverlayHandler($('#overlay1')).
This best way to do this is to make it all relative, so say you have markup like this:
<div class="container">
<div class="overlay">Overlay content</div>
<button class="infoBtn">Click to show overlay</button>
</div>
Then you can find the overlay for this button realtively, like this:
$(function() { //equivalent to $(document).ready(function() {
$('.infoBtn').click(function() {
$(this).closest('.container').find('.overlay').toggleFade(400);
return false;
});
});
You can optimize this further, e.g. .children('.overlay') if the overlay is always a direct child of container. This goes from the current button (this), finds the .container it's in using .closest() and then finds the .overlay inside of it using .find(). With this approach you have one small bit of code to handle all your bindings, much easier to maintain :)

Categories

Resources