Stop propagation on custom event through callback - javascript

I'm not sure how to word it, this is what I'm trying to accomplish:
$(document).on('click', '.my-element', function(e) {
var data = [{
'event': e,
'self': this
}];
// Trigger the override function first in case they need to stop prop
$(document).trigger('override:something',dataa);
// Would like to only trigger this default method if the event above is not set
$(document).trigger('something',data);
});
Then on another page I have something to catch this event, like so:
$(document).on('override:something', function(e,data) {
e.stopImmediatePropagation();
data.e.stopImmediatePropagation(); // neither work
});
If I could stop all subsequent events like this that would be optimal, but I could also make it work if there were a way to check if custom events are set.
I could check whether override:something exists and if it does, do not execute the default something event afterwards.
I've tried setting removing specific callbacks like this, but it did not perform as expected and could get hard to manage.
var mycb = function() {
alert('hi');
}
$(document).on('something', mycb);
// now to remove it
$(document).off('something', mycb); // does not remove the event
Any help is greatly appreciated.

Thanks for the help guys, but this solution seems to the only thing I've found to work for now. Still accepting alternate answers, though.
var override = jQuery._data($(document)[0], 'events')['override:something'];
$(document).trigger('override:something', data);
if ( typeof override == typeof undefined )
$(document).trigger('dashboard:friend', data);

Related

addEventListener("touchstart") doesn’t work on phones [duplicate]

I don't know what I am doing wrong but here is an example of what I am doing and it doesn't seem to work.
someDom.addEventListener('mousemove',function(ev) {self.onInputMove(ev)},false);
someDom.removeEventListener('mousemove',self.onInputMove);
The removeEventListener code is executed but it just doesn't remove the 'mousemove' listener
removeEventListener removes the listener that exactly matches the function that was added.
In this case, the function that addEventListener added was:
var some_func = function(ev) {
self.onInputMove(ev);
};
Store a reference to the actual function and you'll be good. So for example, the following should work:
someDom.addEventListener('mousemove',self.onInputMove,false);
someDom.removeEventListener('mousemove',self.onInputMove,false);
onInputMove is not an event-callback method. So you need to do something like:
var event = function(ev) {self.onInputMove(ev)};
someDom.addEventListener('mousemove', event,false);
someDom.removeEventListener('mousemove', event, false);
Why make it yourself so hard, just use the following to bind an event to an element:
element.onmousemove = function(e) {
// Some code here...
alert("Mouse moved!");
};
Now, when you want to remove the event, just do this:
element.onmousemove = null;
Done!
Hope this helps you guys out!
This page comes first on searching this/such issue on Google. So apart from answers already mentioned, here is one more interesting fact for future:
Leaving out the third optional variable in addEventListener() for useCapture/useBubble (as it defaults to false) does create some issue while removing the same eventlistener with same callback name. I faced this issue while working on chrome. Cant say about other browsers.
So do mention the third variable explicitly as "false".

Creating a custom "event" for a constructor

I am trying to create a custom "event" and I place this inside quotes because it won't be like a regular event per se from the events constructors.
So what I'd like to do is this
animate.addEventListener('animationReadyState',function(e){
if(e.readyState == "complete")
{
console.log("Done");
}
});
var animation = animate(document.getElementById('element'),{
left:"+200px",
top:"+200px",
easing: {
effect: "easeInOutBounce",
elasticity:1.5
}
});
My problem is how to fire off the "event"? I have the readyState changing throughout my code my problem is firing off this "event".
As of right now with using the events contructors I only get one readyState change fired off which is the complete. But I have others
initialising
invoked
animating
complete
No others are firing off.
Example of my Events Constructors:
var animateStateChange = new CustomEvent('animateStateChange',{ 'state' : null });
function initAnimate(){
animateStateChange.state = "initialising";
document.dispatchEvent(animateStateChange);
}
The problem with this is I'd have to do document.addEventListener or the element.addEventListener though putting the event listener on the element that is animating seems logical I'm not sure how to make it only fire from the element and not say on document... Maybe a little crash course on Custom Events or maybe a "hack" event firing system, even examples I can see logically.
This may give a better example of what I am looking for if you to this fiddle
I am not sure if my solution will answer your query, but i tried to use custom events considering situation given above. Also, I see that there is some glitch in dispatchEvent returned value if any handler is provided. Separately i try to return false from handler, but that too din't worked. Below might help you to understand javascript custom event a bit :
Check this link for working code:
http://jsfiddle.net/3q0vubyp/1/
var animation = animate(document.getElementById('element'),{
left:"+200px",
top:"+200px",
easing: {
effect: "easeInOutBounce",
elasticity:1.5
}
});
function handler(e){
if(e.detail.state === "complete"){
alert('Complete State');
return false;
//e.preventDefault();
//e.stopPropagation();
}
}
function animate(element, anim){
var i=0;
var j=true;
var state=['initialize','invoked','animating','complete'];
element.addEventListener('animateStateChange',handler);
while(j){
var animateStateChange = new CustomEvent('animateStateChange',{ 'detail' : {"state": state[i++]} });
//if(!element.dispatchEvent(animateStateChange)){
// j=false;
//}
element.dispatchEvent(animateStateChange);
if(i==4)
j=false;
};
}
In docs of dispatchEvent,doclink It is clearly mentioned that the return value is false if at least one of the event handlers which handled this event called Event.preventDefault(). Otherwise it returns true. That din't worked for me.
Hope that helps!

Can't listen to global event in jQuery

Another question on stackoverflow pointed out that it should be possible to trigger an event on all listning objects using:
$.event.trigger('customEvent');
However this does not seem to work for me in an example like:
$('body').bind('customEvent', function(){ alert('Working!'); });
Am I doing something completely wrong, or has this great functionality been disabled?
It looks like that functionality has been removed. Browsing through the tags I managed to find this TODO in v1.8b1:
// TODO: Stop taunting the data cache; remove global events and always attach to document
And it was removed as of v1.9.0.
There is nothing stopping you from implementing it based on the old source code here (v1.6.2), but it looks like it was doing naughty things talking to jQuery.cache so it's probably best to live without it or come up with another solution.
$('*').trigger('customEvent');
Perhaps? (jsFiddle)
Or a more efficient approach of keeping track of each subscription and calling .trigger() on that.
jsFiddle
var customSubs;
$.fn.subscribeCustom = function (fn) {
this.on('customEvent', fn);
if (!customSubs)
customSubs = this;
else
customSubs = customSubs.add(this);
};
$('span').subscribeCustom(function () {
alert('span!');
});
$('div').subscribeCustom(function () {
alert('div!');
});
customSubs.trigger('customEvent');

How remove onClick, and then add it again later?

I need a method to enable and disable any element. Disable meaning set the opacity to 0.6 and remove the onClick callbacks. Enable meaning set the opacity to 1 and add the callback again.
My first two attempts failed miserably, the callback methods just got stacked and instead of running it once after each click the method was running more and more times.
function disableElement(element){
var el = $('#'+element);
el.css('opacity','0.6');
el.on('click',null); //this doesn't work
el.removeAttr('onClick'); // this doesn't help either.
}
function enableElement(element,callback){
var el = $('#'+element);
el.css('opacity','1');
el.on('click',callback);
}
Then i tried using the el.data:
disableElement:function(element){
var el = $('#'+element);
el.css('opacity','0.6');
el.data('element-enabled','false');
//el.click(function (){
// alert('disabled');
//});
},
enableElement:function(element,callback){
console.log('enabling');
var el = $('#'+element);
console.log(el);
if(el.data('element-enabled') == "true")
return;
console.log("setOpacity");
el.css('opacity','1');
el.data('element-enabled','true');
el.click(function(){
if(el.data('element-enabled') == "true")
callback();
});
}
Now they don't stack, as long as I don't disable it. If I disable and then enable it again, it gets stacked. Which means, if i run enableElement multiple times the callbacks don't stack. But once I run disableElement and then enableElement, if i click in the item, it'll happen twice.
Can achieve that somehow?
UPDATE
That was close. The off worked for me but i also had to remove it on the enableElement. Occasionally I have to call it twice, so it was still stacking. Finally this worked, thank you!
disableElement:function(element){
var el = $('#'+element);
el.css('opacity','0.6');
el.off('click');
},
enableElement:function(element,callback){
var el = $('#'+element);
el.off('click');
el.css('opacity','1');
el.on('click',callback);
}
To remove the event just use .off()
el.off('click');
To add the event back you can just do
el.on('click',callback);
You need to use .off as in .off('click'). That will remove all bound events of the click type. Documentation for .off
Note that if you use .off it doesn't return the event or anything, and you can't simply rebind with .on. However, since you have defined the callback in a separate function, you're good to go since you do re-bind as .on('click', function_name). It's just something to be aware of.
Unbind will remove all handlers assigned to the object for some event:
$('#foo').unbind('click');
You can also set this to some specific function by adding it as a second argument
$('#foo').unbind('click', myfunctionname);

Only register a function with an event once?

I have a jQuery plugin that needs to register a click event handler:
$.fn.myPlugin = function (options) {
var settings = {
// snipped
};
$.extend(settings, options || {});
$("body").click(function () {
// Do Something
});
// Rest of the plugin
});
The problem is that multiple invocations register the function more than once. Since the function needs to stay attached, I can't use .one().
Is there a way if a function is already attached? Can I give it a name or so? Or do I have to set some boolean flag using closure magic?
Namespace your events.
$('body').unbind('click.myPlugin').bind('click.myPlugin', function() {
..code...
});
More on Namespaced Events.
A very easy method with good performance would be to set a data element on the body element:
if (!$.data(document.body, 'myPluginRegistered') {
$.data(document.body, 'myPluginRegistered', true);
// do your plugin code here
}
Easiest might be the boolean plus closure magic you suggested. Alternatively, you could get the list of all functions bound to "click" object, and see if the function you're attaching is there already.
This question shows how to get the list.
List all javascript events wired up on a page using jquery
Though, the namespace suggestion that came in after I first responded is probably simpler.

Categories