How remove onClick, and then add it again later? - javascript

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);

Related

mouse eventlistener isnt being removed

Im trying to remove an eventlistener that I initialize somewhere in the code and then remove later in a function. I know that you have to remove the same listener that you initialized, but it doesnt seem to be working. I store the eventlistener in a variable that I believe has global scope, so Im not sure what the issue is. The eventlistener itself works fine, and starts as expected.
I have also tried not storing the eventlistener in a variable but that didnt work either.
mainFunction = function (){
mousee = document.addEventListener('mouseout', mouseEvent);
if ($(".message_input").val().replace(/\s/g, "").length > 0){
unbindAll(true); // unbind all functions
message = getMessageText(); // retrieve the users message text
$(".message_input_wrapper").html("");
printMessage(message, "right"); // display there message on the screen
if (message=="stop"){
document.removeEventListener(mousee);
initiateStopSection();
} else {
//async_elipsis();
response = async_bot(message);
};
};
};
Just for clarification, I was initially using
document.removeEventListener("mouseout", mouseEvent)
but it wasnt working
When using removeEventListener, you have to pass the event type and the event handler, so in this case you would use
document.removeEventListener("mouseout", mouseEvent)
removeEventListener takes 2 arguments. The first is the event you are trying to target, in this case mouseout, and the second is the function you wish to remove.
For your example it would be this:
document.removeEventListener("mouseout", mouseEvent)
There is no need to set the initial listener to a variable with this implementation.

Stop propagation on custom event through callback

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);

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!

Why are these nested triggers for jQuery not working?

I am using the following code to load two underscore.js templates. Once the first link is clicked, the skeleton template is loaded. The first trigger executes the find bind, which executes the loadBookmarks function correctly, but the 'loaded' trigger never fires and the loadFriendBookmarks never executes. Why is this? Is there another way to make this happen?
$('#bookmarks-link').click(function() {
$('#bookmarks-count').text("0");
var skeleton = modalTemplate();
$('#bookmarks').append(skeleton);
$('#bookmarks').trigger('skeleton');
});
$('#bookmarks').bind('skeleton', function() {
$('#bookmarks .thumbnails').loadBookmarks( getBookmarksUrl(1) );
// If I add an alert('hi') here, it works perfectly.
$('#bookmarks').trigger('loaded');
});
$('#bookmarks').bind('loaded', function() {
$('#bookmarks .thumbnails a').each(function() {
$(this).bind('click', function() {
$('#bookmarks .bookmarks-table tbody').empty();
$('#bookmarks .bookmarks-table tbody').loadFriendBookmarks(
getFriendBookmarksUrl($(this).attr('data-item'))
);
});
});
});
So interesting enough, the triggers do work correctly: If I stick an alert in between loadBookmarks and trigger, everything works fine. If I take it out, then it doesn't. Any idea why?
Based on your description and common sense, it sounds like loadBookmarks() loads data from a remote source, such as an ajax call. This means that trigger('loaded') can fire before loadBookmarks() has received the data. You can add a callback argument to loadBookmarks() and trigger the event there:
$('#bookmarks .thumbnails').loadBookmarks( getBookmarksUrl(1) , function() {
$('#bookmarks').trigger('loaded');
});
But this requires your loadBookmarks to know to call this function after it receives the data and creates the needed HTML - I can't demonstrate this without seeing the actual code you have in loadBookmarks.
Additional suggestion: don't bind handlers this way, use event delegation instead:
$('#bookmarks').on('click', '.thumbnails a', function(e) {
e.preventDefault(); // don't want the link to actually be followed, do we
var url = getFriendBookmarksUrl($(this).attr('data-item'));
if(url) { // in case it's clicked before the data attribute is set
var $tbody = $('#bookmarks .bookmarks-table tbody');
$tbody.empty();
$tbody.loadFriendBookmarks(url);
}
});
This means that all elements matching the selector '#bookmarks .thumbnails a' will call this click handler, even if they were added to the document after you called on. Meaning you can delegate these events even before calling loadBookmarks, removing the need for the loaded event at all. Plus, this way you only have one copy of the handler function in memory, as opposed to your bind which created a separate copy of the function for each a node.
the problem is else where in your code. probably some js error in loadBookmarks* functions.
see:
http://jsfiddle.net/BBESV/
triggers work perfectly

Jquery if its the first time element is being clicked

I need my script to do something on the first time an element is clicked and continue to do something different on click 2,3,4 and so on
$('selector').click(function() {
//I would realy like this variable to be updated
var click = 0;
if (click === 0) {
do this
var click = 1;
} else {
do this
}
});//end click
really I think it should rely on the variables but I can't think of how to update the variable from here on out any help would be awesome.
Have a look at jQuery's .data() method. Consider your example:
$('selector').click(function() {
var $this = $(this),
clickNum = $this.data('clickNum');
if (!clickNum) clickNum = 1;
alert(clickNum);
$this.data('clickNum', ++clickNum);
});
See a working example here: http://jsfiddle.net/uaaft/
Use data to persist your state with the element.
In your click handler,
use
$(this).data('number_of_clicks')
to retrieve the value and
$(this).data('number_of_clicks',some_value)
to set it.
Note: $(this).data('number_of_clicks') will return false if it hasn't been set yet
Edit: fixed link
Another alternative might be to have two functions, and bind one using the one function in $(document).ready() (or wherever you are binding your handlers), and in that function, bind the second function to be run for all subsequent clicks using bind or click.
e.g.
function FirstTime(element) {
// do stuff the first time round here
$(element.target).click(AllOtherTimes);
}
function AllOtherTimes(element) {
// do stuff all subsequent times here
}
$(function() {
$('selector').one('click', FirstTime);
});
This is super easy in vanilla Js. This is using proper, different click handlers
const onNextTimes = function(e) {
// Do this after all but first click
};
node.addEventListener("click", function onFirstTime(e) {
node.addEventListener("click", onNextTimes);
}, {once : true});
Documentation, CanIUse
If you just need sequences of fixed behaviors, you can do this:
$('selector').toggle(function(){...}, function(){...}, function(){...},...);
Event handlers in the toggle method will be called orderly.
$('#foo').one('click', function() {
alert('This will be displayed only once.');
});
this would bind click event to Corresponding Html element once and unbind it automatically after first event rendering.
Or alternatively u could the following:
$("#foo").bind('click',function(){
// Some activity
$("#foo").unbind("click");
// bind it to some other event handler.
});

Categories