I'm using JS modal (no jquery), since I have some issues with that approach...
Everything works good except that on mobile user can't close it.
var modal = document.getElementById('myModal');
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
};
It is probably related to that touch that I'm missing...
I tried with jquery like this:
$(document).ready(function(){
$(modal).on('click touchstart', function() {
modal.style.display = "none";
});
});
The problem here is that if user clicks inside the modal, it will also disappear...
What I need is that when user clicks only outside, modal should disappear...
Any ideas how can I solve this issue?
Thanks.
instead of registering click on the target, register on the document and then check to see that the mouse wasn't inside of the target
$(document).on ('mouseup touchstart', function (e)
{
var container = $("#myModal");
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();
}
});
You can listen for the 'mousedown' event on the document, then check if the modal is in the event path. If it's not, then hide the modal. If it is, then do nothing.
var myModal = document.getElementById('myModal');
document.addEventListener('mousedown', function(e)
{
if (e.path.indexOf(myModal) == -1)
myModal.hidden = true;
});
Have you tried to use contains ?
I just tested it on iOS safari and chrome, it works correctly
please check out the demo,
when you click the yellow part, it still exists
however, when you click the pink part, the whole modal will hide
JS Bin
code in JS Bin
var pa = document.querySelector('#modal-overlay');
var ch = document.querySelector('#modal-container');
pa.addEventListener('click', function(e) {
if (!ch.contains(e.target)) {
pa.style.display = 'none';
}
});
Related
I have a modal box which opens on a button click, when the modal is visible, if the area outside the content box is clicked, then the modal should disappear.
The issue i'm having is that my modal keeps creating the modal and not being completely removed, thus creating a memory leak.
The class show-login-modal handles the visibility of the modal.
let x = 1;
function LoginPopup(){
let modal = document.getElementById('modal');
modal.classList.add('show-login-modal');
let xx = x++;
function _removeModal() {
modal.classList.remove('show-login-modal');
modal.removeEventListener("click", this);
}
modal.addEventListener('click', function(event) {
console.log(xx);
if (event.target === modal) {
_removeModal();
}
});
}
I included the console.log for reference.
What is the best way to fix this?
removeEventListener is being used incorrectly, it needs to be invoked with a named function. So, in your case, you'd want to move the event target detection inside of _removeModal
function _removeModal(event){ if (event.target === this){ ... modal.removeEventListener('click', _removeModal)} }
modal.addEventListener('click', _removeModal)
Now I am not a star really with Javascript, but i seem to encounter the all known problem with mobile devices and the onclick function. Onclick requires a mouse action where off course on the phone that doesnt apply. Now in Jquery, you can use "on" .. but how does this work with regular javascript?
// Get the modal
var modal = document.getElementById('reserveer-modal');
// Get the button that opens the modal
var btn = document.getElementById("reserveer-knop");
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks the button, open the modal
btn.onclick = function() {
var x = window.innerWidth;
if (x > 768) {
//event.preventDefault();
modal.style.display = "block";
} else {
//event.preventDefault();
}
}
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
Try to change onclick to addEventListener and see if that helps you..
// When the user clicks the button, open the modal
btn.addEventListener('click', function () {
var x = window.innerWidth;
if (x > 768) {
//event.preventDefault();
modal.style.display = "block";
} else {
//event.preventDefault();
}
});
You can also pass named function to addEventListener
Binding the click event listener to the element should fix the problem you've been having.
btn.addEventListener("click", function() {
var x = window.innerWidth;
if (x > 768) {
//event.preventDefault();
modal.style.display = "block";
} else {
//event.preventDefault();
}
});
Alternatively, you could try using the touchstart event, which works just like the "mousedown" event, just for mobile.
elem.addEventListener("touchstart", handler);
Your code would look like this:
btn.addEventListener("touchstart", function() {
var x = window.innerWidth;
if (x > 768) {
//event.preventDefault();
modal.style.display = "block";
} else {
//event.preventDefault();
}
});
Had the same issue, after setting z-index to 100 it worked.
Seems like in my case there was a z-index issue.
Make sure you don't have any async/await functions in your code or any arrow functions () => {}. Mobile browsers seem to use older versions of JavaScript before async/await or arrow function were introduced.
I have a button that toggles a menu popup. I have can make the menu disappear if you click outside of the menu but now my button toggle does not work. If I click the button again the menu stays up. How can I make the menu disappear if you toggle the button or if you click off the container?
jsFiddle: http://jsfiddle.net/PPcfN/
$('.quicklinks-rollover').click(function () {
$('.quicklinks').toggle();
});
$(document).mouseup(function (e) {
var container = $(".quicklinks");
if (container.has(e.target).length === 0) {
container.hide();
}
});
The mouseup function has to take care of the click on the button (quicklinks-rollover).
If fixed the whole thing here:
http://jsfiddle.net/8VUnq/1/
$(document).mouseup(function (e) {
var popup = $('#quickLinksPopup'),
button = $('#quickLinksToggle');
if (popup.is(':visible')
&& !popup.is(e.target)
&& !button.is(e.target)
&& popup.has(e.target).length === 0
&& button.has(e.target).length === 0) {
popup.toggle();
}
});
Keep in mind those two things:
Use IDs to refer to the items quicker and prevent multiple popup conflicts
Using a mouse event on the whole page is not recommended as the event will get triggered very frequently, try using an alternative method such as adding a close button in the popup, or to be more effective, think about adding the mouseup listener on the show of the popup and removing it on the hide.
You can determine the state of the popup with: $(popup).is(':visible') or is(':hidden').
Try :
var $quicklinks = $('.quicklinks');
var msOverLinks = false;
$('.quicklinks-rollover').click(function () {
$quicklinks.toggle();
});
$quicklinks.mouseenter(function() {
msOverLinks = true;
}).mouseleave(function() {
msOverLinks = false;
});
$(document).mouseup(function (e) {
if( ! msOverLinks ) {
$quicklinks.toggle();
}
});
You can do this Normal hide and show method. Because mostly toggle() function wont works in proper manner...
put your HTML button with attribute p="closed" by default:
<button class="quicklinks-rollover" p="closed" title="Quick Links">toggle</button>
Change Your Jquery:
$('.quicklinks-rollover').click(function () {
var a = $(this).attr("p");
var container = $(".quicklinks");
if(a=="closed"){
container.show();
$(this).attr("p","open");
}else{
container.hide();
$(this).attr("p","closed");
}
});
$(document).mouseup(function (e) {
var container = $(".quicklinks");
if (container.has(e.target).length === 0) {
container.hide();
}
});
The reason for this behavior, the mouseup() is binded when I perform the click() on the div. You can check this behavior by adding console.log message in .mouseup event.
So instead try like below.
$('.quicklinks-rollover').on('click', function (e) {
$('.quicklinks').toggle();
e.stopImmediatePropagation();
});
$(document).click(function (e) {
var container = $(".quicklinks");
console.log(container.has(e.target).length);
if (container.has(e.target).length === 0) {
container.hide();
}
});
Working Fiddle
I'm using twitter bootstrap to display popovers with a click event. I'm requesting the info with the click event but I want to hide the popover after it looses focus so the user isn't required to click it again. Is this possible?
Basically I want to show the popover with a click event but then when the launch point looses focus from the mouse the popover is hidden.
Here is a link to the popover doc from twitter-bootstrap: http://twitter.github.com/bootstrap/javascript.html#popovers
This is what I'm currently doing:
jQuery:
$('.knownissue').on('click', function() {
var el = $(this);
if (el.data('showissue') == 'true') {
el.popover('toggle');
el.data('showissue', 'false');
return;
}
$.post('functions/get_known_issues.php', function(data) {
if (data.st) {
el.attr('data-content', data.issue);
el.popover('toggle');
el.data('showissue', 'true');
}
}, "json");
});
Any thoughts?
The following should work.
$('.knownissue').mouseleave(function() {
$(this).popover('hide');
});
Here is a custom jQuery event I call 'clickoutside'. It gets fired if and only if you click the mouse outside of the target element. It could easily be adapted for other event types (mousemove, keydown, etc). In your case, when fired it could close your modal.
(function ($) {
var count = 0;
$.fn.clickoutside = function (handler) {
// If the source element does not have an ID, give it one, so we can reference it
var self = $(this);
var id = self.attr('id');
if (id === '') {
id = 'clickoutside' + count++;
self.attr('id', id);
}
// Watch for the event everywhere
$('html').click(function (e) {
var source = $(e.target);
// ... but, stop it from propagating if it is inside the target
// element. The result being only events outside the target
// propagate to the top.
if (source.attr('id') == id || source.parents('#' + id).length > 0) {
return;
}
handler.call(this, e);
})
};
})(jQuery);
$('#targetElement').clickoutside(function(){
});
EDIT: Example JSFiddle.
I have written some JavaScript that opens an element when an element is clicked. However I can't get the:
var menu = document.getElementById(show);
if (menuOpen && e.target !== menu){...}
This is not working to how I want it because:
You can open more than one of the showed elements when I only want one open at a time.
When I click inside the element it closes, I only want it to close if they have clicked outside the box.
function openBox(button, show){
var menuOpen = false; //to toggle when the button is clicked.
// checks the whole document for clicks and then if the element is open it will >
// check to see if you have clicked away from it or not.
document.addEventListener("click", function(e){
var menu = document.getElementById(show);
if (menuOpen && e.target !== menu){ // if elements open and the click event target does not match >
menu.style.display = "none"; // we will close it
menuOpen = false;
}
},false);
// add an event listner to the button element and then if its clicked stop any >
// links an stop bubbling and then change the display style.
document.getElementById(button).addEventListener("click", function(e){
var menu = document.getElementById(show);
e.preventDefault();
e.stopPropagation();
if (menuOpen){
menu.style.display = "none";
menuOpen = false;
} else {
menu.style.display = "block";
menuOpen = true;
}
},false);
}
openBox("signInButton", "signIn");
openBox("bagButton", "shoppingBag");
openBox("currencyButton", "currencySelect");
http://jsfiddle.net/jamcoupe/9CEGw/
Edit:
After #Felix Kling post I changed the code to:
document.addEventListener("click", function(e){
var menu = document.getElementById(show);
if (menuOpen && (e.target.parentNode !== menu) && (e.target !== menu)){
menu.className = "closedBoxes";
pointer = document.getElementById(arrow).className = "arrowE";
menuOpen = false;
}
},false);
This has solve the first problem but I am still stuck on how to make it so that only one box is ever open at one giving time. So when a user has signIn box open and clicks on currencyChanger I want the signIn box to be off.
http://jsfiddle.net/jamcoupe/kcF9Z/7/
When I click inside the element it closes, I only want it to close if they have clicked outside the box.
As I already said in my comment, if the box contains other elements, then e.target does not refer to the box itself but to the element within the box.
So in order to test whether the click was outside or not, you have to test whether e.target is an element within the box or the box itself. For that, you have to traverse the DOM tree.
Example:
var target = e.target;
while(target && target !== menu) {
target = target.parentNode;
}
if(!target) {
// click was outside of the box
}
You can open more than one of the showed elements when I only want one open at a time.
If you want to make the three dialogs dependent on each other, you have to maintain some shared state. I'd suggest, instead of having three dialogs, you can have one dialog manager which takes care of opening and closing the boxes.
Example:
function DialogManager() {
this.dialogs_ = {};
this.openedDialog_ = null;
this.init_();
}
DialogManager.prototype.init_ = function(e) {
var self = this;
document.addEventListener('click', function(e) {
var id = e.target.id;
if(id && id in self.dialogs_) { // if one of the buttons was clicked.
self.openDialog(id); // the dialog is opened (or closed)
return;
}
if(self.openedDialog_) { // if a dialog is currently open, we have to
var target = e.target; // close it if the click was outside
while(target && target.id !== self.openedDialog_) {
target = target.parentNode;
}
if(!target) {
self.closeDialog(self.openedDialog_);
}
}
}, false);
};
DialogManager.prototype.registerDialog = function(button_id, dialog_id) {
this.dialogs_[button_id] = dialog_id;
};
DialogManager.prototype.openDialog = function(id) {
var open_id = this.openedDialog_;
if(open_id) {
this.closeDialog(open_id);
}
if(id !== open_id) {
var dialog = document.getElementById(this.dialogs_[id]);
dialog.style.display = "block";
this.openedDialog_ = id;
}
};
DialogManager.prototype.closeDialog = function(id) {
var dialog = document.getElementById(this.dialogs_[id]);
dialog.style.display = "none";
this.openedDialog_ = null;
};
DEMO
I hope this gives you some idea. There is still a lot which can be improved, for example, now the manager listens to every click event, no matter whether a dialog is open or not.