Trigger event if click outside selector - javascript

I'm trying to click somewhere other than the button, hide the element, but I do not get it, I have no idea how to do it.
$(function(){
$(document).on('click','#foo',function(){
let div = $('#bar');
if( div.css('display') === 'none' ){
div.show();
}
else{
div.hide();
}
});
})
#foo{
min-width: 35%;
}
#bar{
max-width: 35%;
min-height: 100px;
background-color: aliceblue;
border: 1px solid blue;
border-radius: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="foo">Toggle</button><br><br>
<div id="bar"></div>
I got an idea but it doesn´t work.
$(document).on('click','html',function(e){
if(e.eventTarget !== 'foo'){
$('#bar').hide();
}
});
I got 2 issues, if the selector is html, the page will not answer, and the code in, is just to show what I'm trying to get.

No need for jQuery, you can simply test to see if .closest('#bar') exists:
const bar = document.querySelector('#bar');
let hidden = false;
document.body.addEventListener('click', (e) => {
if (e.target.closest('#foo')) {
console.log('clicked inside, returning');
return;
}
console.log('clicked outside');
bar.style.display = hidden ? 'block' : 'none';
hidden = !hidden;
});
body {
height: 200px;
}
#foo{
min-width: 35%;
}
#bar{
max-width: 35%;
min-height: 100px;
background-color: aliceblue;
border: 1px solid blue;
border-radius: 5px;
}
<button id="foo">Toggle</button>
<div id="bar"></div>

You may have to consume events bubbling up to parent node.
$(function() {
$('#foo').on('click', function(e) {
e.stopPropagation();
e.preventDefault();
$('#bar').toggle();
console.log('toggle ... bar');
});
$(document).on('click', function(e) {
e.stopPropagation();
e.preventDefault();
$('#bar').hide();
console.log('hide ... bar');
});
})
#foo {
min-width: 35%;
}
#bar {
max-width: 35%;
min-height: 100px;
background-color: aliceblue;
border: 1px solid blue;
border-radius: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="foo">Toggle</button><br><br>
<div id="bar"></div>

I think it is better way to use focus and blur functions for that
Here is how I did
<button id="test">
Hello
</button>
<div class="blue-container" tabindex="1">
</div>
The tabindex global attribute indicates if its element can be focused
$('#test').focus(function () {
$('.blue-container').show().focus();
});
$('.blue-container').blur(function () {
$('.blue-container').hide();
});

This is the simplest approach.
$(document).on("click",function() {
if(event.target.id == 'foo') {
//if #foo is clicked, do nothing
}
else {
//if the button is not clicked
$('#bar').hide();
}
});
#foo{
min-width: 35%;
}
#bar{
max-width: 35%;
min-height: 100px;
background-color: aliceblue;
border: 1px solid blue;
border-radius: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="foo">Toggle</button><br><br>
<div id="bar"></div>

Related

Toggle change 2 DIV width at a time + localStorage

function myFunction() {
var element = document.getElementById("one1");
element.classList.toggle("one2");
var element = document.getElementById("two1");
element.classList.toggle("two2");
}
<style>
#section{margin-left:50px;
margin-right:50px
}
#monbouton{float:right;
font-size:25px;
width:50px;
height:50px;
background-color:#F1F1F1;
border:1px solid ##F1F1F1
}
#one1{
float:left;
width:40%;
height:100px;
border:1px solid blue
}
.one2{
width:10% !important;
height:200px;
border:1px solid red !important;
}
.one2 #afairedisparaitre{display:none
}
#two1{float:right;
width:59%;
height:100px;
border:1px solid green
}
.two2{width:89% !important
}
</style>
<!DOCTYPE html>
<html>
<body>
<div id="section">
<div id="one1">
<button id="monbouton" onclick="myFunction()">↔</button>
<div id="afairedisparaitre">This is DIV #one1<br />
Button toggle to CLASS .one2<br />
and reverse</div>
</div>
<div id="two1">This is DIV #two1<br />
Button toggle to CLASS .two2<br />
and reverse</div>
</div>
</body>
</html>
I am trying to make the leftside of my website shrink, so that the users can have a wider rightside if they find it more confortable.
What I am missing is a way that would keep the choice all over the site, when an other page is loaded, until the user clicks again. Maybe the solution would be a few more lines in js with "localStorage" ? I would really appreciate any help.
Made your CSS a bit better. Now we need to toggle only one class .with_toggle for #section.
It can sow errors here, in Snippet, but will fork fine on Codepan, see please. Try to switch it and reload the page on Codepan.
// checking if our storage is not empty
if (localStorage.toggled != '') {
// set class to #section form storage value
document.getElementById("section").classList.toggle(localStorage.toggled);
}
function myFunction() {
if (localStorage.toggled != "with_toggle") {
document.getElementById("section").classList.add("with_toggle");
localStorage.toggled = "with_toggle";
} else {
document.getElementById("section").classList.remove("with_toggle");
localStorage.toggled = "";
}
}
#section {
margin-left: 50px;
margin-right: 50px;
}
#monbouton {
float: right;
font-size: 25px;
width: 50px;
height: 50px;
background-color: #F1F1F1;
border: 1px solid #F1F1F1;
}
#one1 {
float: left;
width: 40%;
height: 100px;
border: 1px solid blue;
}
.with_toggle #one1 {
width: 10%;
border: 1px solid red;
}
.with_toggle #one1 #afairedisparaitre {
display: none;
}
#two1 {
float: right;
width: 59%;
height: 100px;
border: 1px solid green;
}
.with_toggle #two1 {
width: 89%;
}
<div id="section">
<div id="one1">
<button id="monbouton" onclick="myFunction()">↔</button>
<div id="afairedisparaitre">This is DIV #one1<br /> Button toggle to CLASS .one2<br /> and reverse</div>
</div>
<div id="two1">This is DIV #two1<br /> Button toggle to CLASS .two2<br /> and reverse</div>
</div>
Sure. Just create a localStorage variable that keeps track of whether the shrink should be active and use that to apply your styles on page load or something similar.
function shrinkActive() {
var shrink;
if (!(shrink = localStorage.getItem("shrink"))) {
localStorage.setItem("shrink", "false");
return false;
}
return JSON.parse(shrink);
}
function setShrink(active) {
var element1 = document.getElementById("one1");
var element2 = document.getElementById("two1");
if (active) {
element1.classList.add("one2");
element2.classList.add("two2");
} else {
element1.classList.remove("one2");
element2.classList.remove("two2");
}
localStorage.setItem("shrink", active.toString());
}
function myFunction() {
setShrink(!shrinkActive());
}
window.onload = function() {
setShrink(shrinkActive());
}
Link to working Codepen. https://codepen.io/bugcatcher9000/pen/pogZbrz?editors=1111

JQuery Traversing through DOM on click

I am having problem of traversing through each HTML element one by one.There are two buttons #up and #down.On click of #up the id #myID should move to the next element upwards and vice versa for #down.The problem is I am able to move through the siblings but not through the child elements.
For example if I click on #down the id #myID should have moved to p tag which is the child of that div on next click to span which is child of p then on next click to div.But in my code it is directly jumping to div ignoring the children.
JSFIDDLE
Here is the code:
$("#up").click(function() {
$("#startHere").find("#myID").next().attr('id', 'myID');
$('#startHere').find("#myID").removeAttr('id');
});
$("#down").click(function() {
$("#startHere").find("#myID").prev().attr('id', 'myID');
$('#startHere').find("#myID").next().removeAttr('id');
})
#myID {
border: 2px solid yellow;
}
#startHere {
height: 100%;
width: 50%;
}
div {
height: 100px;
width: 100px;
border: 2px solid;
margin: 10px;
}
p {
height: 50px;
width: 50px;
border: 2px solid blue;
margin: 10px;
}
h1 {
height: 40px;
width: 40px;
border: 2px solid red;
margin: 10px;
}
span {
display: block;
height: 25px;
width: 25px;
border: 2px solid green;
margin: 10px;
}
button {
height: 25px;
width: 100px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="up">GO DOWN</button>
<button id="down">GO UP</button>
<div id="startHere">
<div id="myID">
<p><span></span></p>
</div>
<div><span></span></div>
<div>
<h1></h1>
</div>
<p></p>
<h1></h1>
<p><span></span></p>
</div>
I think you can just find all the elements first, jQuery returns them in DOM order, which is what you want. No need to search for the next/prev element on-the-fly.
var allElements = $("#startHere").find('*');
var currentIndex = allElements.index('#myID');
function move(delta) {
// Find the new index
var index = currentIndex + delta;
// Clamp to 0…lengh of list
// Here we could also make it wrap instead
index = Math.max(Math.min(index, allElements.length - 1), 0);
// Remove the ID from the old element
allElements.eq(currentIndex).removeAttr('id');
// Add the ID to the new element
allElements.eq(index).attr('id', 'myID');
// Update the index
currentIndex = index;
}
$("#up").click(function() {
move(1);
});
$("#down").click(function() {
move(-1);
})
var allElements = $("#startHere").find('*');
var currentIndex = allElements.index('#myID');
function move(delta) {
// Find the new index
var index = currentIndex + delta;
// Clamp to 0…lengh of list
// Here we could also make it wrap instead
index = Math.max(Math.min(index, allElements.length - 1), 0);
// Remove the ID from the old element
allElements.eq(currentIndex).removeAttr('id');
// Add the ID to the new element
allElements.eq(index).attr('id', 'myID');
// Update the index
currentIndex = index;
}
$("#up").click(function() {
move(-1);
});
$("#down").click(function() {
move(1);
})
#myID {
border: 2px solid yellow;
}
#startHere {
height: 100%;
width: 50%;
}
div {
height: 100px;
width: 100px;
border: 2px solid;
margin: 10px;
}
p {
height: 50px;
width: 50px;
border: 2px solid blue;
margin: 10px;
}
h1 {
height: 40px;
width: 40px;
border: 2px solid red;
margin: 10px;
}
span {
display: block;
height: 25px;
width: 25px;
border: 2px solid green;
margin: 10px;
}
button {
height: 25px;
width: 100px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="down">GO DOWN</button>
<button id="up">GO UP</button>
<div id="startHere">
<div id="myID">
<p><span></span></p>
</div>
<div><span></span></div>
<div>
<h1></h1>
</div>
<p></p>
<h1></h1>
<p><span></span></p>
</div>
If you do need the elements on-the-fly (because they might have changed), you can still use the same tactic (and simply build up the allElements list in the move function and get the index using allElements.index('#myID')) but it might be more performant to update the list only when you know it changed (after an Ajax request, after modification on event handlers, etc.).
Edit:
The code for searching the next/prev element on-the-fly is a bit more work because it has to recurse when traversing up but makes it possible to have a different set of rules for up vs. down movement.
var boundary = $("#startHere");
function findNext(node, anchor) {
if(!anchor && node.children(':first-child').length) {
return node.children(':first-child');
}
if(node.next().length) {
return node.next();
}
if(!boundary.find(node.parent()).length) {
// Out of boundary. Stick to the last node
return anchor||node;
}
return findNext(node.parent(), anchor||node);
}
function findPrev(node, anchor) {
if(!anchor && node.children(':last-child').length) {
return node.children(':last-child');
}
if(node.prev().length) {
return node.prev();
}
if(!boundary.find(node.parent()).length) {
// Out of boundary. Stick to the last node
return anchor||node;
}
return findPrev(node.parent(), anchor||node);
}
function move(finder) {
// Find the current item
var current = boundary.find('#myID');
// Find the next item
var next = finder(current);
// Remove the ID from the old element
current.removeAttr('id');
// Add the ID to the new element
next.attr('id', 'myID');
}
$("#up").click(function() {
move(findPrev);
});
$("#down").click(function() {
move(findNext);
})
var boundary = $("#startHere");
function findNext(node, anchor) {
if(!anchor && node.children(':first-child').length) {
return node.children(':first-child');
}
if(node.next().length) {
return node.next();
}
if(!boundary.find(node.parent()).length) {
// Out of boundary. Stick to the last node
return anchor||node;
}
return findNext(node.parent(), anchor||node);
}
function findPrev(node, anchor) {
if(!anchor && node.children(':last-child').length) {
return node.children(':last-child');
}
if(node.prev().length) {
return node.prev();
}
if(!boundary.find(node.parent()).length) {
// Out of boundary. Stick to the last node
return anchor||node;
}
return findPrev(node.parent(), anchor||node);
}
function move(finder) {
// Find the current item
var current = boundary.find('#myID');
// Find the next item
var next = finder(current);
// Remove the ID from the old element
current.removeAttr('id');
// Add the ID to the new element
next.attr('id', 'myID');
}
$("#up").click(function() {
move(findPrev);
});
$("#down").click(function() {
move(findNext);
})
#myID {
border: 2px solid yellow;
}
#startHere {
height: 100%;
width: 50%;
}
div {
height: 100px;
width: 100px;
border: 2px solid;
margin: 10px;
}
p {
height: 50px;
width: 50px;
border: 2px solid blue;
margin: 10px;
}
h1 {
height: 40px;
width: 40px;
border: 2px solid red;
margin: 10px;
}
span {
display: block;
height: 25px;
width: 25px;
border: 2px solid green;
margin: 10px;
}
button {
height: 25px;
width: 100px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="down">GO DOWN</button>
<button id="up">GO UP</button>
<div id="startHere">
<div id="myID">
<p><span></span></p>
</div>
<div><span></span></div>
<div>
<h1></h1>
</div>
<p></p>
<h1></h1>
<p><span></span></p>
</div>
This is really bad UI. To select some nodes in some states, you first have to navigate “UP” and then “DOWN” again. But it seems to do what you ask for.

How to check if the click was directly in an element or some of its children only?

I don't want clicks on children other than some, and the parent div itself to trigger any events.
Please see this, which does not do what I want:
https://jsfiddle.net/k12e8rgt/3/
$(document).ready(function() {
$('#parent').on('click', function(event) {
alert("you clicked directly on me!");
});
});
you can use event.target
Example :
$(document).ready(function() {
$("div").on("click", function(event) {
alert("You click on : " + event.target.tagName)
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div>this is Div
<p>This is p</p>
</div>
Assign a class to elements which are to be ignored
Use .hasClass() to determine whether any of the matched elements are assigned the given class
$('#parent').on('click', function(event) {
if ($(event.target).hasClass('ignore')) {
alert("Ignore !");
} else {
alert("Do something!");
}
});
#parent {
width: 200px;
height: 200px;
background-color: blue;
color: white;
}
#child2 {
background-color: white;
color: red;
margin: 10px;
}
#child1 {
background-color: white;
color: green;
margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="parent">it should trigger here
<div id="child1">and here</div>
<div id="child2" class="ignore">but not here, and there are many of this kind</div>
</div>
If there are set of ids which are to be ignored, use event.target.id property and test the value against it!
$('#parent').on('click', function(event) {
if (event.target.id === 'child2' || event.target.id === 'child3') {
alert("Ignore !");
} else {
alert("Do something!");
}
});
#parent {
width: 200px;
height: 200px;
background-color: blue;
color: white;
}
#child2 {
background-color: white;
color: red;
margin: 10px;
}
#child3 {
background-color: white;
color: red;
margin: 10px;
}
#child1 {
background-color: white;
color: green;
margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="parent">it should trigger here
<div id="child1">and here</div>
<div id="child2">but not here, and there are many of this kind</div>
<div id="child3">but not here, and there are many of this kind</div>
</div>
Use event.target...
https://api.jquery.com/event.target/
Also, for event handling in general with jQuery...
https://learn.jquery.com/events/handling-events/

Checking Clicked Element in Bubbling

I was tinkering with event bubbling and I created the typical 3 divs each other exercise for myself and I was able to get the code working and event to stop "bubbling" where I wanted.
My code was clunky so I tried to make it a little more simplified. By having all my <divs> point to a single function, that had a statement that said if this <div> was clicked, run the function and then stop propagation, but I believe the way I am "checking" the click is wrong.
Link: https://jsfiddle.net/theodore_steiner/t5r5kov0/3/
var d1 = document.getElementById("d1");
var d2 = document.getElementById("d2");
var d3 = document.getElementById("d3");
function showme(event) {
if (d3.onclick == true) {
alert("hello")
event.stopPropagation();
} else {
alert("hello");
}
};
d1.addEventListener("click", showme);
d2.addEventListener("click", showme);
d3.addEventListener("click", showme);
#d1 {
height: 300px;
width: 300px;
border: 1px solid black;
}
#d2 {
height: 200px;
width: 200px;
border: 1px solid black;
}
#d3 {
height: 100px;
width: 100px;
border: 1px solid black;
}
<div id="d1">
<div id="d2">
<div id="d3">
</div>
</div>
</div>
Use event.target.id as event.target will return element on which event is invoked and id is a property of the DOMElement
Event.target, A reference to the object that dispatched the event.
var d1 = document.getElementById("d1");
var d2 = document.getElementById("d2");
var d3 = document.getElementById("d3");
function showme(event) {
if (event.target.id == 'd3') {
alert("hello")
event.stopPropagation();
} else {
alert("hello");
}
};
d1.addEventListener("click", showme);
d2.addEventListener("click", showme);
d3.addEventListener("click", showme);
#d1 {
height: 300px;
width: 300px;
border: 1px solid black;
}
#d2 {
height: 200px;
width: 200px;
border: 1px solid black;
}
#d3 {
height: 100px;
width: 100px;
border: 1px solid black;
}
<div id="d1">
<div id="d2">
<div id="d3">
</div>
</div>
</div>

How to attach div to mouse pointer so it will work properly during scrolling

I'm trying to attach some kind of tips above buttons and show them on hover so they will appear directly aside to mouse pointer. I want to store text for those tips in data-attributes of buttons and create them dynamically using jquery. I use .pageX .pageY stuff to find coordinates of cursor, but it's working fine only in certain point of scroll.
$('button').mouseenter(function (e) {
var data = $(this).data('value');
if(data){
$('<div />', {
'class' : 'tip',
text : $(this).data('value'),
css : {
position: 'fixed',
top: e.pageY-230,
left: e.pageX+15
}
}).appendTo(this);
}
})
.mouseleave(function () {
$('.tip', this).remove();
})
.mousemove(function (e) {
$('.tip', this).css({
top: e.pageY-230,
left: e.pageX+15
});
})
button {
margin: 10px;
}
.divs {
width: 100%;
height: 350px;
background-color: #ddd;
margin: 0px;
}
.tip {
border: 1px solid #eee;
background: #fff;
box-shadow: 3px 4px 6px rgba(0,0,0,0.4);
padding: 3px;
font-weight: bolder;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="divs"></div>
<button data-value="Per">First</button>
<button data-value="Aspera">Second</button>
<button data-value="Ad">Third</button><br>
<button data-value="Astra">Yadi</button>
<button data-value="To infinity">Yada</button>
<button data-value="and beyond!">Bla-bla</button>
<div class="divs"></div>
You better watch it: http://jsfiddle.net/millerJr/ps8vf8ce/
So, how to attach those tips to pointer directly, regardless to scroll position? Thanks!
You need to use e.clientX and e.clientY in this manner
top: e.clientY+$(this).height() and left: e.clientX+$(this).width()/2 for bottom center of this element in scope. You can add anything else wrt the current element hovered upon
e.clientX and e.clientY will provide the exact mouse co-ordinates
Snippet Below
$('button').mouseenter(function (e) {
var data = $(this).data('value');
if(data){
$('<div />', {
'class' : 'tip',
text : $(this).data('value'),
css : {
position: 'fixed',
top: e.clientY+$(this).height(),
left: e.clientX+$(this).width()/2
}
}).appendTo(this);
}
})
.mouseleave(function () {
$('.tip', this).remove();
})
.mousemove(function (e) {
$('.tip', this).css({
top: e.clientY+$(this).height(),
left: e.clientX+$(this).width()/2
});
})
button {
margin: 10px;
}
.divs {
width: 100%;
height: 350px;
background-color: #ddd;
margin: 0px;
}
.tip {
border: 1px solid #eee;
background: #fff;
box-shadow: 3px 4px 6px rgba(0,0,0,0.4);
padding: 3px;
font-weight: bolder;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="divs"></div>
<button data-value="Per">First</button>
<button data-value="Aspera">Second</button>
<button data-value="Ad">Third</button><br>
<button data-value="Astra">Yadi</button>
<button data-value="To infinity">Yada</button>
<button data-value="and beyond!">Bla-bla</button>
<div class="divs"></div>

Categories