ChatGPT解决这个技术问题 Extra ChatGPT

Use jQuery to hide a DIV when the user clicks outside of it

I am using this code:

$('body').click(function() {
   $('.form_wrapper').hide();
});

$('.form_wrapper').click(function(event){
   event.stopPropagation();
});

And this HTML:

<div class="form_wrapper">
   <a class="agree" href="javascript:;">I Agree</a>
   <a class="disagree" href="javascript:;">Disagree</a>
</div>

The problem is that I have links inside the div and when they no longer work when clicked.

Using plain javascript you can try something like this: jsfiddle.net/aamir/y7mEY
using $('html') or $(document) would be better than $('body')

佚名

Had the same problem, came up with this easy solution. It's even working recursive:

$(document).mouseup(function(e) 
{
    var container = $("YOUR CONTAINER SELECTOR");

    // if the target of the click isn't the container nor a descendant of the container
    if (!container.is(e.target) && container.has(e.target).length === 0) 
    {
        container.hide();
    }
});

Just put it in my project, but with a minor adjustment, using an array of elements to loop through them all at once. jsfiddle.net/LCB5W
@mpelzsherman Many people commented that the snippet works on touch devices but since the post has been edited these comments have somewhat vanished. TBH I don't know whether I used "mouseup" for a specific reason but if it also works with "click" I see no reason why you shouldn't use "click".
I needed that the container is hide one time with this event, this callback should be destroyed when used. To do that, i used namespace on click event with bind("click.namespace") and when the event occurred, i call unbind("click.namespace"). And finally, i used $(e.target).closest(".container").length to recognize container ... So, i did not use any trick from this answer :D
Remembering to use $("YOUR CONTAINER SELECTOR").unbind( 'click', clickDocument ); just beside .hide(). So document don't keep listening for clicks.
For best practices I'd wrote $(document).on("mouseup.hideDocClick", function () { ... }); in the function that opens the container, and $(document).off('.hideDocClick'); on hide function. Using namespaces I'm not removing other possible mouseup listeners attached to the document.
M
Makram Saleh

You'd better go with something like this:

var mouse_is_inside = false;

$(document).ready(function()
{
    $('.form_content').hover(function(){ 
        mouse_is_inside=true; 
    }, function(){ 
        mouse_is_inside=false; 
    });

    $("body").mouseup(function(){ 
        if(! mouse_is_inside) $('.form_wrapper').hide();
    });
});

How clever! Is this technique standard?
@advait I didn't see it used before. It's all about the hover event handler, which opens up many possibilities.
I don't consider this to be a good solution since it lets people think it is okay to populate the window-object (= using global variables).
Just to add something to what @prc322 said, you can wrap your code with an anonymous function and have it called immediately. (function() { // ... code })(); I don't remember the name os this pattern, but it's super useful! All your declared variables will reside inside the function and won't pollute the global namespace.
@prc322 If you don't even know how to change a variable's scope, then you're right, this solution is not good for you... and neither is JavaScript. If you're just copying and pasting code from Stack Overflow, you're gonna have a lot more problems than possibly overwriting something in the window object.
C
Case

This code detects any click event on the page and then hides the #CONTAINER element if and only if the element clicked was neither the #CONTAINER element nor one of its descendants.

$(document).on('click', function (e) {
    if ($(e.target).closest("#CONTAINER").length === 0) {
        $("#CONTAINER").hide();
    }
});

This is perfect!!
@9KSoft I am glad it was able to help you. Thank you for your feedback and best of luck.
This solution worked perfectly for me using a div as container!
This worked for me for a sidebar submenu displayed on the right
D
David Andres

You might want to check the target of the click event that fires for the body instead of relying on stopPropagation.

Something like:

$("body").click
(
  function(e)
  {
    if(e.target.className !== "form_wrapper")
    {
      $(".form_wrapper").hide();
    }
  }
);

Also, the body element may not include the entire visual space shown in the browser. If you notice that your clicks are not registering, you may need to add the click handler for the HTML element instead.


Yep, now the links work! But for some reason, when I click the link, it fires it twice.
I ended up using a variation of this. I first check if the element is visible then if the target.hasClass I hide it.
and dont forget e.stopPropagation(); if you have other click listener
-1. This hides the form_wrapper when you click one of its children, which isn't the desired behaviour. Use prc322's answer instead.
@Tallboy, I appreciate your perspective here. I get it, it's better to not waste vertical space, at least when you need to print code. I have heard it said that condensing braces makes code more readable, but I would argue that the code within these methods should already be short enough to fit on a screen regardless of where braces are placed. If not, then there may be bigger issues at hand. Years ago, I found the balanced approach to brace placement more aesthetically pleasing but over time have transitioned to the form you recommend.
T
The Codesee

Live DEMO

Check click area is not in the targeted element or in it's child

$(document).click(function (e) {
    if ($(e.target).parents(".dropdown").length === 0) {
        $(".dropdown").hide();
    }
});

UPDATE:

jQuery stop propagation is the best solution

Live DEMO

$(".button").click(function(e){
    $(".dropdown").show();
     e.stopPropagation();
});

$(".dropdown").click(function(e){
    e.stopPropagation();
});

$(document).click(function(){
    $(".dropdown").hide();
});

Thanks for the update, perfect! Does it work on touch devices?
In the case, you have multiple dropdowns on a page. I think you will need to close all dropdowns before opening the clicked one. Otherwise, the stopPropagation would make possible that multiple dropdowns are open at the same time.
Thanks a lot, in my case propagation was the only working solution
$(".dropdown").click(function(e){ e.stopPropagation(); }); this is working fine for me ... thanks
I preferred this method, thanks!
m
meder omuraliev
$(document).click(function(event) {
    if ( !$(event.target).hasClass('form_wrapper')) {
         $(".form_wrapper").hide();
    }
});

Hmmm... If I click on something INSIDE the div, the entire div disappears for some reason.
Instead of checking if the target has the class, try: if ( $(event.target).closest('.form_wrapper).get(0) == null ) { $(".form_wrapper").hide(); } This will insure that clicking things inside of the div won't hide the div.
C
Community

A solution without jQuery for the most popular answer:

document.addEventListener('mouseup', function (e) {
    var container = document.getElementById('your container ID');

    if (!container.contains(e.target)) {
        container.style.display = 'none';
    }
}.bind(this));

MDN: https://developer.mozilla.org/en/docs/Web/API/Node/contains


bind there doesn't work. Could you fix the function to make it work?
b
benvds

Updated the solution to:

use mouseenter and mouseleave instead

of hover use live event binding

var mouseOverActiveElement = false;

$('.active').live('mouseenter', function(){
    mouseOverActiveElement = true; 
}).live('mouseleave', function(){ 
    mouseOverActiveElement = false; 
});
$("html").click(function(){ 
    if (!mouseOverActiveElement) {
        console.log('clicked outside active element');
    }
});

.live is now deprecated; use .on instead.
R
Roko C. Buljan

Live demo with ESC functionality

Works on both Desktop and Mobile

var notH = 1,
    $pop = $('.form_wrapper').hover(function(){ notH^=1; });

$(document).on('mousedown keydown', function( e ){
  if(notH||e.which==27) $pop.hide();
});

If for some case you need to be sure that your element is really visible when you do clicks on the document: if($pop.is(':visible') && (notH||e.which==27)) $pop.hide();


N
Nishant

Wouldn't something like this work?

$("body *").not(".form_wrapper").click(function() {

});

or

$("body *:not(.form_wrapper)").click(function() {

});

This answer is not correct. Like many answers here, this will hide the .form_wrapper when you click its children (among other problems).
O
Oscar

Instead of listening to every single click on the DOM to hide one specific element, you could set tabindex to the parent <div> and listen to the focusout events.

Setting tabindex will make sure that the blur event is fired on the <div> (normally it wouldn't).

So your HTML would look like:

<div class="form_wrapper" tabindex="0">
    <a class="agree" href="javascript:;">I Agree</a>
    <a class="disagree" href="javascript:;">Disagree</a>
</div>

And your JS:

$('.form_wrapper').on('focusout', function(event){
    $('.form_wrapper').hide();
});

O
Olivenbaum

Even sleaker:

$("html").click(function(){ 
    $(".wrapper:visible").hide();
});

This answer is not correct. This will hide the .wrapper no matter where you click on the page, which isn't what was asked for.
z
zak

So many answers, must be a right of passage to have added one... I didn't see a current (jQuery 3.1.1) answers - so:

$(function() {
    $('body').on('mouseup', function() {
        $('#your-selector').hide();
    });
});

C
Code Spy

And for Touch devices like IPAD and IPHONE we can use following code

$(document).on('touchstart', function (event) {
var container = $("YOUR CONTAINER SELECTOR");

if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
    {
        container.hide();
    }
});

s
shngrdnr

(Just adding on to prc322's answer.)

In my case I'm using this code to hide a navigation menu that appears when the user clicks an appropriate tab. I found it was useful to add an extra condition, that the target of the click outside the container is not a link.

$(document).mouseup(function (e)
{
    var container = $("YOUR CONTAINER SELECTOR");

    if (!$("a").is(e.target) // if the target of the click isn't a link ...
        && !container.is(e.target) // ... or the container ...
        && container.has(e.target).length === 0) // ... or a descendant of the container
    {
        container.hide();
    }
});

This is because some of the links on my site add new content to the page. If this new content is added at the same time that the navigation menu disappears it might be disorientating for the user.


d
djv

Here's a jsfiddle I found on another thread, works with esc key also: http://jsfiddle.net/S5ftb/404

    var button = $('#open')[0]
    var el     = $('#test')[0]

    $(button).on('click', function(e) {
      $(el).show()
      e.stopPropagation()
    })

    $(document).on('click', function(e) {
      if ($(e.target).closest(el).length === 0) {
        $(el).hide()
      }
    })

    $(document).on('keydown', function(e) {
      if (e.keyCode === 27) {
        $(el).hide()
      }
    })

I see it detects whether the 'click' event is within the #test element.. tried tesing links as jsfiddle.net/TA96A & looks like they might work.
Yes, it looks like jsfiddle blocks outside links. If you use http:// jsfiddle.net you'll see the result page processes the link :)
W
WiseOlMan

Built off of prc322's awesome answer.

function hideContainerOnMouseClickOut(selector, callback) {
  var args = Array.prototype.slice.call(arguments); // Save/convert arguments to array since we won't be able to access these within .on()
  $(document).on("mouseup.clickOFF touchend.clickOFF", function (e) {
    var container = $(selector);

    if (!container.is(e.target) // if the target of the click isn't the container...
        && container.has(e.target).length === 0) // ... nor a descendant of the container
    {
      container.hide();
      $(document).off("mouseup.clickOFF touchend.clickOFF");
      if (callback) callback.apply(this, args);
    }
  });
}

This adds a couple things...

Placed within a function with a callback with "unlimited" args Added a call to jquery's .off() paired with a event namespace to unbind the event from the document once it's been run. Included touchend for mobile functionality

I hope this helps someone!


C
Community

if you have trouble with ios, mouseup is not working on apple device.

does mousedown /mouseup in jquery work for the ipad?

i use this:

$(document).bind('touchend', function(e) {
        var container = $("YOURCONTAINER");

          if (container.has(e.target).length === 0)
          {
              container.hide();
          }
      });

G
Gary
var n = 0;
$("#container").mouseenter(function() {
n = 0;

}).mouseleave(function() {
n = 1;
});

$("html").click(function(){ 
if (n == 1) {
alert("clickoutside");
}
});

A
AlexVogel
 $('body').click(function(event) {
    if (!$(event.target).is('p'))
    {
        $("#e2ma-menu").hide();
    }
});

p is the element name. Where one can pass the id or class or element name also.


u
user3151197

Copied from https://sdtuts.com/click-on-not-specified-element/

Live demo http://demos.sdtuts.com/click-on-specified-element

$(document).ready(function () {
    var is_specified_clicked;
    $(".specified_element").click(function () {
        is_specified_clicked = true;
        setTimeout(function () {
            is_specified_clicked = false;
        }, 200);
    })
    $("*").click(function () {
        if (is_specified_clicked == true) {
//WRITE CODE HERE FOR CLICKED ON OTHER ELEMENTS
            $(".event_result").text("you were clicked on specified element");
        } else {
//WRITE CODE HERE FOR SPECIFIED ELEMENT CLICKED
            $(".event_result").text("you were clicked not on specified element");
        }
    })
})

This is genuis.
b
bogo

Return false if you click on .form_wrapper:

$('body').click(function() {
  $('.form_wrapper').click(function(){
  return false
});
   $('.form_wrapper').hide();
});

//$('.form_wrapper').click(function(event){
//   event.stopPropagation();
//});

T
ThornberryPie

Attach a click event to top level elements outside the form wrapper, for example:

$('#header, #content, #footer').click(function(){
    $('.form_wrapper').hide();
});

This will also work on touch devices, just make sure you don't include a parent of .form_wrapper in your list of selectors.


S
SharmaPattar

var exclude_div = $("#ExcludedDiv");; $(document).click(function(e){ if( !exclude_div.is( e.target ) ) // if target div is not the one you want to exclude then add the class hidden $(".myDiv1").addClass("hidden"); });

FIDDLE


R
RustBeard

$(document).ready(function() { $('.modal-container').on('click', function(e) { if(e.target == $(this)[0]) { $(this).removeClass('active'); // or hide() } }); }); .modal-container { display: none; justify-content: center; align-items: center; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); z-index: 999; } .modal-container.active { display: flex; } .modal { width: 50%; height: auto; margin: 20px; padding: 20px; background-color: #fff; }


j
jeffsaracco

What you can do is bind a click event to the document that will hide the dropdown if something outside the dropdown is clicked, but won't hide it if something inside the dropdown is clicked, so your "show" event (or slidedown or whatever shows the dropdown)

    $('.form_wrapper').show(function(){

        $(document).bind('click', function (e) {
            var clicked = $(e.target);
            if (!clicked.parents().hasClass("class-of-dropdown-container")) {
                 $('.form_wrapper').hide();
            }
        });

    });

Then when hiding it, unbind the click event

$(document).unbind('click');

u
user2822517

i did it like this:

var close = true;

$(function () {

    $('body').click (function(){

        if(close){
            div.hide();
        }
        close = true;
    })


alleswasdenlayeronclicknichtschliessensoll.click( function () {   
        close = false;
    });

});

A
Abed Yaseen
dojo.query(document.body).connect('mouseup',function (e)
{
    var obj = dojo.position(dojo.query('div#divselector')[0]);
    if (!((e.clientX > obj.x && e.clientX <(obj.x+obj.w)) && (e.clientY > obj.y && e.clientY <(obj.y+obj.h))) ){
        MyDive.Hide(id);
    }
});

S
Steve Zelaznik

By using this code you can hide as many items as you want

var boxArray = ["first element's id","second element's id","nth element's id"];
   window.addEventListener('mouseup', function(event){
   for(var i=0; i < boxArray.length; i++){
    var box = document.getElementById(boxArray[i]);
    if(event.target != box && event.target.parentNode != box){
        box.style.display = 'none';
    }
   }
})

C
Cody Gray

According to the docs, .blur() works for more than the <input> tag. For example:

$('.form_wrapper').blur(function(){
   $(this).hide();
});

-1, doesn't work. Very interesting idea, but the jQuery docs are wrong. See developer.mozilla.org/en-US/docs/Web/API/…, for instance: "In contrast to MSIE--in which almost all kinds of elements receive the blur event--almost all kinds of elements on Gecko browsers do NOT work with this event." Also, tested in Chrome, and divs never blur - blur events can't even bubble to them from their children. Finally, even if the above weren't true, this would only work if you made sure that the .form_wrapper was in focus before the user clicked off it.