I'm not exactly sure how to phrase this, so I couldn't search it. Basically, I have a keydown() bind on $(document). I'd like to show() another div, and have all keydown events be rerouted to this div and prevented from firing off in the document handler. Is this even possible, or would I have to put all my main keybindings on another div and work from there?
e.stopPropagation, or
e.preventDefault (depending on the situation)
Where e is the event.
Ex:
function onKeyDown(e) {
doStuff();
e.preventDefault();
}
e.preventDefault() will prevent the default behaviour of an event. What you need is to use
e.stopPropagation(), so that the event does not bubble up the DOM structure.
$(element).keydown(function(e) {
// do the task
// allow the default behaviour also
e.stopPropagation();
//^. BUT stop the even bubbling up right here
});
e.stopProgation(), can be bit confusing to grasp on the first but I created a demo with click event to explain it.
Hope it helps!!
Try:
$(document).on('keydown', function (evt) {
$('#foo').show().trigger(evt);
});
$('#foo').on('keydown', function (evt) {
console.log(evt);
return false; // this is very important. Without it, you'll get an endless loop.
});
demo: http://jsfiddle.net/Z7vYK/
The only way I can think of to even have a keydown event run on something other than an input or document, is to manually trigger it. You could have a global variable keep track of whether or not your div is showing, then trigger the event on your div accordingly.
Here's one such solution
HTML
Show div
<div id="hiddendiv"></div>
Javascript
var showing = false;
function showdiv()
{
showing = true;
$('#hiddendiv').show(200);
}
// Set up events on page ready
$(function() {
$(document).keydown(function(e) {
// If the div is showing, trigger it's keydown
// event and return
if(showing)
{
$('#hiddendiv').data('keydown_event', e).keydown();
return true;
}
alert('Document keydown! Keycode: ' + e.keyCode);
// Otherwise do the normal keydown stuff...
});
// Keydown for the hidden div
$('#hiddendiv').keydown(function() {
e = $(this).data('keydown_event');
alert('Hiddendiv keydown! Keycode: ' + e.keyCode);
// Make sure to stop propagation, or the events
// will loop for ever
e.stopPropagation();
return false;
});
});
As you can see, the #hiddendiv keydown event is being triggered by the document keydown event. I've also included a slight hack to get the event object to the hidden div using the jQuery data function.
Here's a demonstration of the code: http://jsfiddle.net/Codemonkey/DZecX/1/
Related
I have some code that runs on a "blur" event on an element.
This code needs to actually use the activeElement, and thus can't actually run from the "blur" event.
I was hoping I could create an event like this. The aim was that the "willblur" event would fire before the "blur" event.
var lastTouchedElement;
$('body').on('click', preBlurHandler);
$('body').on('focusin', postFocusHandler);
$('.inp1').on('willblur', function() {alert('willblur');});
$('.inp1').on('blur', function() {alert('blur');});
function preBlurHandler(ev) {
if (!lastTouchedElement) {
postFocusHandler(ev);
return;
}
var focussingElement = ev.target;
if (lastTouchedElement === focussingElement || $.contains(lastTouchedElement, focussingElement)) {
//focus is staying in the same place, do nothing
return;
}
$(lastTouchedElement).trigger('willblur', [ev, {
target: lastTouchedElement,
focussingElement: focussingElement
}]);
}
function postFocusHandler(ev) {
lastTouchedElement = document.activeElement;
}
The full code is in JSFiddle at https://jsfiddle.net/t0un95jt/3/
But it doesn't work. In fact it's not even close.
Help me StackOverflow; you're my only hope.
The key was to use addEventListener instead of JQuery's on(), and to use "mousedown" instead of "click".
instead of this line:
$('body').on('click', preBlurHandler);
I use this:
window.addEventListener('mousedown', preBlurHandler, true);
The final argument for addEventListener: true, means "do this on the capturing phase". The capturing phase starts at the outermost element and works its way through firing an event on subsequent child elements, before the bubbling phase begins which works its way back up the DOM tree.
I am working on a firebug like javascript element selector, but cannot figure out how to stop all JavaScript events from firing when clicked. The firebug lite plugin (https://getfirebug.com/firebuglite) is doing exactly what I want, but cannot figure out what they are doing.
Any help would be appreciated.
Senario:
User selects element inspector
User clicks on element
onClick, mousedown, mouseup should NOT fire
I have tried the following with no luck:
function stopEvents(el){
for(var key in window) {
if (key.indexOf("on") == 0)
el.addEventListener(key.substr(2), stop, false);
}
}
function StopEvent(pE)
{
stopEvents(pE);
if (!pE)
if (window.event)
pE = window.event;
else
return;
if (pE.cancelBubble != null)
pE.cancelBubble = true;
if (pE.stopPropagation)
pE.stopPropagation();
if (pE.preventDefault)
pE.preventDefault();
if (window.event)
pE.returnValue = false;
if (pE.cancel != null)
pE.cancel = true;
}
EDIT:
$('.somediv').on("click", function(e){
//Stop bubbling and propagation
StopEvent(e);
//EDIT: Still not working with this
e.stopImmediatePropagation();
//RUN only my code here
console.log("My code is running still");
return false;
});
If there is another library such as YUI binding events to the same DOM element. It will fire there event after mine. I cannot seem to hijack the event to stop this from happening.
EDIT:
I cannot use disabled because I need to be able to fire my event. If I did the following, I wouldn't be able to fire the above event. I cannot attach a parent event either because the DOM will stop firing all events on the Tree for that node.
$('.somediv').on("mouseover", function(e){
$(this).attr("disabled", "disabled");
});
EDIT:
The events I want to disable are already created before my script runs. These events could be any javascript library such as YUI, Dojo, jQuery, JavaScript etc...
Disabling all events on the page is very easy. Hard part is to restore them when needed.
document.body.innerHTML = document.body.innerHTML;
This will effectively remove all events bound to DOM nodes by replacing the DOM with it's "virgin" copy.
Most of the time user won't even notice the redraw.
You can't "disable" all of them without also intercepting the actual event binding, so you'd have to end up with something like this:
(function(prototypes) {
prototypes.forEach(function(prototype) {
var eventTracker = {};
var oldAEL = prototype.addEventListener;
prototype.addEventListener = function(a,b,c) {
if (!eventTracker[a]) { eventTracker[a] = true; }
return oldAEL.call(this, a, function(evt) {
console.log(a, eventTracker[a]);
if(eventTracker[a] === true) {
b(evt);
}
},c);
};
prototype.toggleEvent = function(name, state) {
eventTracker[name] = state;
};
});
}([Document.prototype, HTMLElement.prototype, ...]));
example: http://jsfiddle.net/BYSdP/1/
the button gets three click listeners, but if the second button is clicked, the event regulator for "click" is set to false, so none of the events will actually trigger the originally supplied code. Note that this also makes debugging a LOT harder, because you're wrapping handlers in anonymous functions.
event.stopImmediatePropagation() keeps the rest of the handlers from being executed and prevents the
event from bubbling up the DOM tree.
Example:
$( "p" ).click(function( event ) {
event.stopImmediatePropagation();
});
$( "p" ).click(function( event ) {
// This function won't be executed
$( this ).css( "background-color", "#f00" );
});
Source: https://api.jquery.com/event.stopimmediatepropagation/
I am having trouble with multiple clicks being registered in jQuery when only one element has been clicked. I have read some other threads on Stack Overflow to try and work it out but I reckon it is the code I have written. The HTML code is not valid, but that is caused by some HTML 5 and the use of YouTube embed code. Nothing that affects the click.
The jQuery, triggered on document.ready
function setupHorzNav(portalWidth) {
$('.next, .prev').each(function() {
$(this).click(function(e) {
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
});
function initiateScroll(target) {
var position = $(target).offset();
$('html, body').animate({
scrollLeft: position.left
}, 500);
}
}
Example HTML
<nav class="prev-next">
Prev
Next
</nav>
In Firefox one click can log a "Click!" 16 times! Chrome only sees one, but both browsers have shown problems with the above code.
Have I written the code wrongly or is there a bug?
-- Some extra info ------------------------------------------
setupHorzNav is called by another function in my code. I have tested this and have confirmed it is only called once on initial load.
if ( portalWidth >= 1248 ) {
wrapperWidth = newWidth * 4;
setupHorzNav(newWidth);
}
else
{
wrapperWidth = '100%';
}
There are mutiple instances of nav 'prev-next'. All target different anchors. All are within the same html page.
<nav class="prev-next">
Prev
</nav>
Try unbinding the click event like this
$(this).unbind('click').click(function (e) {
});
You don't need .each() for binding event handlers. Try this instead:
$('.next, .prev').click(function(e){
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
EDIT:
I think it is the way you are attaching the event handler from within the setupHorzNav function that is causing it. Change it to attach it only once from say, $(document).ready() or something.
I have managed to get the situation of multiple event handlers by attaching the event handlers from a function that gets called from event handler. The effect is that the number of click event handlers keeps increasing geometrically with each click.
This is the code: (and the jsfiddle demo)
function setupNav() {
$('.next, .prev').each(function () {
$(this).click(function (e) {
setupNav();
var target = $(this).attr('href');
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
});
}
setupNav();
See how calling the setupNav() function from the click event handler adds multiple eventhandlers (and the click log message) on successive clicks
Since it is not clear from your question whether you are calling the binding function multiple times, a quick and dirty fix would be:
$('.next, .prev').unbind('click').click(function() {
...
});
What you are doing here is unbinding any previously bound event handlers for click and binding afresh.
Are there no other click bindings elsewhere?
Are you loading the page with ajax?
You could also try this:
$('.next, .prev').click(function (e) {
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
<body>
<div id="aaa">
<div id="bbb">
</div>
</div>
</body>
$(#?????).click(function(){
$('#bbb').hide();
})
http://jsfiddle.net/GkRY2/
What i must use if i want hide #bbb if user click outside box #bbb? But if i click on div #bbb then box is still visible - only outside.
$('body').click(function(e){
if( e.target.id == 'bbb' )
{ return true; }
else
{ $('#bbb').hide(); }
});
A note of explanation: There are a few ways to do this, either way we need to listen for a click on a parent element, weather it be a direct parent like #aaa or a distant parent like the body or the document. This way we can capture clicks that occur outside of #bbb.
Now that we have that we need the .hide to NOT occur if the user did click inside of #bbb. We can do this two ways
Stop propagation if the user clicks on #bbb. This will make the click event not 'bubble' up to the parent. That way the click event never reaches the parent and so #bbb will not hide. I personally don't like this method because stop propagation will so ALL click events from bubbling, and you may have click events that you would like to bubble to a local parent and not a distant parent. Or you may have listeners delegated from a distant parent, which will stop working if click propagation is stopped.
Check for the #bbb element in the parent listener. This is the method shown above. Basically this listens on a distant parent, and when a click occurs it checks to see if that click is on #bbb specifically. If it IS NOT on #bbb .hide is fired, otherwise it returns true, so other things that may be tied into the click event will continue working. I prefer this method for that reason alone, but secondarily its a-little bit more readable and understandable.
Finally the manner in which you check to see if the click originated at #bbb you have many options. Any will work, the pattern is the real meat of this thing.
http://jsfiddle.net/tpBq4/ //Modded from #Raminson who's answer is very similar.
New suggestion, leverage event bubbling without jQuery.
var isOutSide = true
bbb = documment.getElementById('bbb');
document.body.addEventListener('click', function(){
if(!isOutSide){
bbb.style.display = 'none';
}
isOutSide = true;
});
bbb.addEventListener('click', function(){
isOutSide = false;
});
Catch the click event as it bubbles-up to the document element. When it hits the document element, hide the element. Then in a click event handler for the element, stop the propagation of the event so it doesn't reach the document element:
$(function () {
$(document).on('click', function () {
$('#bbb').hide();
});
$('#bbb').on('click', function (event) {
event.stopPropagation();
});
});
Here is a demo: http://jsfiddle.net/KVXNL/
Docs for event.stopPropagation(): http://api.jquery.com/event.stopPropagation/
I made a plugin that does this. It preserves the value for this where as these other solutions' this value will refer to document.
https://github.com/tylercrompton/clickOut
Use:
$('#bbb').clickOut(function () {
$(this).hide();
});
You can use target property of the event object, try the following:
$(document).click(function(e) {
if (e.target.id != 'bbb') {
$('#bbb').hide();
}
})
DEMO
This will work
$("#aaa").click(function(){
$('#bbb').hide();
});
$("#bbb").click(function(event){
event.stopPropagation();
})
Becouse bbb is inside the aaa the event will "bubbel up to aaa". So you have to stop the bubbling by using the event.stopPropagation when bbb is clicked
http://jsfiddle.net/GkRY2/5/
OK
* this is none jquery. you can easly modify it to work with IE
first create helper method to facilitate codding don't get confused with JQuery $()
function $g(element) {
return document.getElementById(element);
}
create our listener class
function globalClickEventListener(obj){
this.fire = function(event){
obj.onOutSideClick(event);
}
}
let's say we need to capture every click on document body
so we need to create listeners array and initialize our work. This method will be called on load
function initialize(){
// $g('body') will return reference to our document body. parameter 'body' is the id of our document body
$g('body').globalClickEventListeners = new Array();
$g('body').addGlobalClickEventListener = function (listener)
{
$g('body').globalClickEventListeners.push(listener);
}
// capture onclick event on document body and inform all listeners
$g('body').onclick = function(event) {
for(var i =0;i < $g('body').globalClickEventListeners.length; i++){
$g('body').globalClickEventListeners[i].fire(event);
}
}
}
after initialization we create event listener and pass reference of the object that needs to know every clcik on our document
function goListening(){
var icanSeeEveryClick = $g('myid');
var lsnr = new globalClickEventListener(icanSeeEveryClick);
// add our listener to listeners array
$g('body').addGlobalClickEventListener(lsnr);
// add event handling method to div
icanSeeEveryClick.onOutSideClick = function (event){
alert('Element with id : ' + event.target.id + ' has been clicked');
}
}
* Take into account the document body height and width
* Remove event listeners when you don't need them
$(document).click(function(event) {
if(!$(event.target).closest('#elementId').length) {
if($('#elementId').is(":visible")) {
$('#elementId').hide('fast');
}
}
})
Change the "#elementId" with your div.
I'd like to somehow be able to define with JavaScript an onclickout event. That is something that happens when the user clicks anywhere else that the element in question.
I tried with onblur but it just don't seem to work :/
Is there any other way?
This uses the jQuery help, but the logic is the same if you prefer without it.
$(document).mouseup(function(event) {
var condition = $(event.target).parents(/* element_in_question */).length;
if (condition == 0) { // 0 means the event is not originated from the element in question
// Do what you need to do
}
}
});
document.getElementById('click').onclick = function(event) {
event.stopPropagation();
}
document.onclick = function() {
alert('click somewhere else');
}
jsFiddle.
This will send a click anywhere (except on #click) to the document.onclick handler, which will fire the alert().
You can set a variable, clickedin, on an element's click handler, and then have a click handler for the document that is checking if clickedin is true, and if it is, handle appropriately.
There may be a better way to accomplish the same end, though.