Bubbling events in IE - javascript

all
Now I defined a change click for checkbox,when chexkbox checked,I will show a tips,I also defined click in my HTML ,when I click everywhere,I will hide a tips,but my problem is When I checked the checkbox,the tips is not show in IE,I
through debugger,I find the Body click is Trigger,is it a Bubbling events?I try write
window.event ? window.event.cancelBubble = true : e.stopPropagation();
,but it is not work,body click still Trigger in IE,in Google isn’t have this problem,how to deal with it?
$(document).on("change", ".checked", function (self) {
$(".circle_bot").show();
window.event ? window.event.cancelBubble = true : e.stopPropagation();
}
$("body").click(function () {
$(".circle_bot").hide();
});
<body>
...
<div class="circle_bot"></div>
...
<input type="checkbox" class="checked"/>
</body>
I want to only trigger check click,isn't trigger body click when chenced the checkbox.

You can check what target of click was and do something like:
$("body").click(function(event) {
// don't do anything if checkbox clicked
if (!$(event.target).is('.checked')) {
$(".circle_bot").hide();
}
});
note that jQuery provides event object in all event handlers so you don't have to see if window.event is available, it is done for you

Related

Prevent function execution twice within two triggered events

I have the following code:
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
The problem with the above is when I click myButton both events are triggered and triggerProcess() is fired twice which is not desired.
I only need triggerProcess() to fire once. How can I do that?
Small demo
You can have a static flag that disables any more triggers once the first trigger has occurred. Might look something like this:
var hasTriggered = false;
myInput.change(function (e) { // this triggers first
triggerProcess();
});
myButton.click(function (e) { // this triggers second
triggerProcess();
});
function triggerProcess () {
// If this process has already been triggered,
// don't execute the function
if (hasTriggered) return;
// Set the flag to signal that we've already triggered
hasTriggered = true;
// ...
}
For resetting the hasTriggered flag, that's entirely up to you and how this program works. Maybe after a certain event occurring in the program you'd want to reenable the ability to trigger this event again — all you'd need to do it set the hasTriggered flag back to true.
You can use the mousedown event, which will fire before the input is blurred, and then check if the input has focus by checking if it's the activeElement, and if it does have focus, don't fire the mousedown event, as the change event will fire instead.
Additionally, if you want a mousedown event to occur when the value hasn't changed, and the change event doesn't fire, you'll need a check for that as well
var myInput = $('#test1'),
myButton = $('#test2'),
i = 0;
myInput.change(function(e) { // this triggers first
$(this).data('prev', this.value);
triggerProcess();
});
myButton.mousedown(function(e) { // this triggers second
var inp = myInput.get(0);
if (document.activeElement !== inp || inp.value === myInput.data('prev'))
triggerProcess();
});
function triggerProcess() {
console.log('triggered : ' + (++i))
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="test1">
<br />
<br />
<button id="test2">
Click
</button>
In a fairly typical scenario where you have an input with a button next to ie, eg quick search.
You want to fire when the input changes (ie onblur) but also if the user clicks the button.
In the case where the user changes the input then clicks the button without changing input focus (ie no blur), the change event fires because the text has changed and the click event fires because the button has been clicked.
One option is to debounce the desired event handler.
You can use a plugin or a simple setTimeout/clearTimeout, eg:
$('#inp').change(debounceProcess)
$('#btn').click(debounceProcess);
function debounceProcess() {
if (debounceProcess.timeout != null)
clearTimeout(debounceProcess.timeout);
debounceProcess.timeout = setTimeout(triggerProcess, 100)
}
function triggerProcess() {
console.log('process')
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input id="inp">
<button id="btn">Click</button>
Use a real <button>BUTTON</button>. If you click on input text, alert is triggered, then once you leave the input text to click anywhere else, that unfocuses the input text which triggers the change event, so now 2 events have been triggered from the text input.
This is an assumption since the code provided is far from sufficient to give a complete and accurate answer. The HTML is needed as well as more jQuery/JavaScript. What is myInput and myButton actually referring to, etc.?
So I bet if you change...
var myButton = $('{whatever this is}'); and <input type='button'>
...TO:
var myButton = $("button"); and <button></button>
...you should no longer have an event trigger twice for an element.
This is assuming that triggerProcess() is a function that does something that doesn't manipulate the event chain or anything else involving events. This is an entirely different ballgame if instead of click() and change() methods you are using .trigger() or triggerHandler(), but it isn't. I'm not certain why such complex answers are derived from a question with very little info...?
BTW, if myInput is a search box and myButton is the button for myInput, as freedomn-m has mentioned, simply remove:
myButton.click(...
Leave myButton as a dummy. The change event is sufficient in that circumstance.
SNIPPET
var xInput = $('input');
var xButton = $('button'); //«———Add
xInput.on('change', alarm);
xInput.on('click', alarm);
xButton.on('click', alarm);
function alarm() {
return alert('Activated')
}
/* For demo it's not required */
[type='text'] {
width: 5ex;
}
b {
font-size: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id='f1' name='f1'>
<input type='text'>
<input type='button' value='BUTTON TYPE'>
<label><b>⇦</b>Remove this button</label>
<button>BUTTON TAG</button>
<label><b>⇦</b>Replace it with this button</label>
</form>

button click not working first time in ipad

This is my html code
< button class="send-report" name="submit" id="submit" type="submit" onclick="reportfeed()">Send Report< /button>
On the first click the keyboard disappeared, the 'reportfeed' function works only in the second click (in ipad)
function reportfeed()
{
alert(1);
}
I can use the code below, Please help me if you know any other method
jQuery(".send-report").bind("click touchstart", function(){
reportfeed();
});
Define a clickhandler that you can use later on:
var clickHandler = ('ontouchstart' in document.documentElement ? "touchstart" : "click");
$(".send-report").bind(clickHandler, function(e) {
alert("clicked or tapped. This button used: " + clickHandler);
});
This will trigger click on non-touch devices and touchstart on touch devices.
Use .on() because .bind() will be removed from future scripts,I think.
Try this
$(".send-report").on('touchstart click', function(){
reportfeed();
});
You could use .stopPropagation() to stop multiple events being fired. Also, if you want to do specific stuff for different event types use e.type
$('.send-report').on('touchstart click', function(e) {
e.stopPropagation(); //stops propagation
if(e.type == "touchstart") {
// Handle touchstart event.
} else if(e.type == "click") {
// Handle click event.
}
});

JavaScript prevent touch move on body element, enable on other elements

but very simply, I'd like to prevent the touchmove event on the body element but leave it enabled for another element. I can disable fine... but I'm not sure how to re-enable it somewhere else!
I imagine that the below theoretically works because return true is the opposite of preventDefault, but it doesn't work for me. Might be 'cause $altNav element is in $bod?
JS:
$bod.bind('touchmove', function(event){
event.preventDefault();
});
$altNav.bind('touchmove', function(event){
return true;
});
I'm not sure what lib you're actually using, but I'll asume jQuery (I'll also post the same code in browser-native-js if you're using something other than jQ)
$bod.delegate('*', 'touchstart',function(e)
{
if ($(this) !== $altNav)
{
e.preventDefault();
//and /or
return false;
}
//current event target is $altNav, handle accordingly
});
That should take care of everything. The callback here deals with all touchmove events, and invokes the preventDefault method every time the event was triggered on an element other than $altNav.
In std browser-js, this code looks something like:
document.body.addEventListener('touchmove',function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
//in case $altNav is a class:
if (!target.className.match(/\baltNav\b/))
{
e.returnValue = false;
e.cancelBubble = true;
if (e.preventDefault)
{
e.preventDefault();
e.stopPropagation();
}
return false;//or return e, doesn't matter
}
//target is a reference to an $altNav element here, e is the event object, go mad
},false);
Now, if $altNav is an element with a particular id, just replace the target.className.match() thing with target.id === 'altNav' and so on...
Good luck, hope this helps
Use a custom CSS class and test for it in the document handler, eg:
<div>
This div and its parents cannot be scrolled.
<div class="touch-moveable">
This div and its children can.
</div>
</div>
then:
jQuery( document ).on( 'touchmove', function( ev )
{
if (!jQuery( ev.target ).parents().hasClass( 'touch-moveable' ))
{
ev.preventDefault();
}
});
http://tinyurl.com/mo6vwrq
you can add a argument,like this
$bod.bind('touchmove', function(event,enable){
if(enable){
event.preventDefault();
}
});

Why does jQuery's one fire immediately when it's added to an element?

Here's a fiddle illustrating the problem. I am adding a jQuery one binding on the click of one element to the 'html' element. I am not expecting the 'one' event handler to fire until the next click, but it fires on the click that adds the binding. This seems to not be a problem if it is a more specific element that the 'one' event handler is added to, but it happens when I use 'html' or 'body' as the element, which is what I want to do.
This doesn't make sense to me, I'd think the first click would add the one for the next click and it wouldn't fire on the click on the link.
By the way, my actual problem could probably be solved in a better way, but I came across this and was curious why it didn't work as I expected.
Code:
html:
<div id='hello'>hello</div>
<a class="title" href="#">this example</a> is a test​
js:
$(function() {
$('a.title').click(function() {
var htmlClickBind = function (e) {
console.log('clicked on html, e.target = ' + e.target);
console.log(e.target == '');
if (!$(e.target).is('a') ) {
console.log('cleared click event');
}
else {
$('html').one('click', htmlClickBind);
}
};
$('html').one('click', htmlClickBind);
});
});​
The click event on the a.target element bubbles up to the html element, where your (just-added) handler sees it.
To prevent this, use event.stopPropgation in your a.target click handler (or return false, which does stopPropagation and preventDefault).
Updated code (see the comments): Live copy
$(function() {
// Accept the event arg ----v
$('a.title').click(function(e) {
// Stop propagation
e.stopPropagation();
var htmlClickBind = function (e) {
console.log('clicked on html, e.target = ' + e.target);
console.log(e.target == '');
if (!$(e.target).is('a') ) {
console.log('cleared click event');
}
else {
$('html').one('click', htmlClickBind);
}
};
$('html').one('click', htmlClickBind);
});
});​

jquery selector help. Everything but the specified selector

I have the following function to open an overlay menu:
$('.context-switch').click(function() {
$(".context-switch-menu").toggle();
});
To hide the menu, I would like the user to be able to click on any area outside ".context-switch-menu"
I am trying with :not() but with no success..
$('body').click(function(e) {
if ($(e.target).hasClass('context-switch')) {
return;
}
$(".context-switch-menu").hide();
});
$('.context-switch').click(function() {
$(".context-switch-menu").toggle();
return false;
});
The reason this can be difficult is because of event bubbling.
You can try something like this:
$('.context-switch').click(function(e) {
e.stopPropagation();
$(".context-switch-menu").toggle();
});
$(".context-switch-menu").click(function(e){
e.stopPropagation();
});
$("body").click(function(e){
$(".context-switch-menu").hide();
});
The e.stopPropagation() prevents the click event from bubbling to the body handlers. Without it, any click to .context-switch or .context-switch-menu would also trigger the body event handler, which you don't want, as it would nullify the effect of the .context-switch click half the time. (ie, if the state is hidden, and then you click to show, the event would bubble and trigger the body handler that would then hide the .context-switch-menu again.)
Without testing, would something like this work?:
$('.context-switch').click(function() {
$(".context-switch-menu").show();
});
$(document).click(function() {
$(".context-switch-menu").hide();
});
Instead of using document, 'html' or 'body' may work as well.
$(document).on('click', function(e) {
if (e.target.className !='context-switch-menu') {
$(".context-switch-menu").hide();
}
});
Just an idea here, based on what what others have suggested in the past:
$(document).click(function(e){
//this should give you the clicked element's id attribute
var elem = $(e.target).attr('classname');
if(elem !== 'context-switch-menu'){
$('.context-switch-menu').slideUp('slow');
//or however you want to hide it
}
});
try this, we don't want to call a function when you clicked on the element itself, and not when we click inside the element. That's why we need 2 checks.
You want to use e.target which is the element you clicked.
$("html").click(function(e){
if( !$(e.target).is(".context-switch-menu") &&
$(e.target).closest(".context-switch-menu").length == 0
)
{
alert("CLICKED OUTSIDE");
}
});
Live fiddle: http://jsfiddle.net/Xc25K/1/

Categories