function bubble(content, triggerElm){
this.element = $('<div class="bubble" />').html(content);
this.element.css(.....) // here is positioned based on triggerElm
}
bubble.prototype.show = function(){
$(document).on('click', this._click.bind(this));
this.element.css(....)
};
bubble.prototype.hide = function(){
$(document).off('click', this._click.bind(this));
this.element.css(....)
};
bubble.prototype._click = function(event){
console.log('click', this);
if(this.element.is(event.target) || (this.element.has(event.target).length > 0))
return true;
this.hide();
};
var b = new bubble();
b.show();
b.hide();
I keep seeing click in the console, so the click does not unbind.
But if I remove the bind() call the click is unbinded. Does anyone know why? I need a way to be able to change "this" inside my test function, that's why I'm using bind().
The problem is that this._click.bind() creates a new function every time it's called. In order to detach a specific event handler, you need to pass in the original function that was used to create the event handler and that's not happening here, so the handler is not removed.
If there are only going to be a few bubbles in your app, you could and simply not use this. That will remove a lot of the confusion about what this is referring to and ensure that each bubble retains a reference to its own click function that can be used to remove the event as needed:
function bubble(content, triggerElm) {
var element = $('<div class="bubble" />').html(content);
element.css(.....); // here is positioned based on triggerElm
function click(event) {
console.log('click', element);
if (element.is(event.target) ||
element.has(event.target).length > 0) {
return true;
}
hide();
}
function show() {
$(document).on('click', click);
element.css(....);
}
function hide() {
$(document).off('click', click);
element.css(....);
}
return {
show: show,
hide: hide
};
}
var b1 = bubble(..., ...);
b1.show();
var b2 = bubble(..., ...);
b2.show();
See how this frees you from using contrivances like .bind() and underscore-prefixed methods.
One option would be to namespace the event:
$(document).on('click.name', test.bind(this));
$(document).off('click.name');
Example Here
try use jQuery's proxy to get a unique reference of your function.
In this way, when you call $.proxy(test, this), it will check if this function has already been referenced before. If yes, proxy will return you that reference, otherwise it will create one and return it to you. So that, you can always get your original function, rather than create it over and over again (like using bind).
Therefore, when you call off(), and pass it the reference of your test function, off() will remove your function from click event.
And also, your test function should be declared before use it.
var test = function(){
console.log('click');
};
$(document).on('click', $.proxy(test, this));
$(document).off('click', $.proxy(test, this));
http://jsfiddle.net/aw50yj7f/
Please read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
bind creates a new function therefore doing $(document).on('click', test.bind(this)); is like $(document).on('click', function(){}); and each time you execute it you invoke a new anonymous function thus you dont have a reference to unbind.
If you would do something like:
var test = function(){
console.log('click');
};
var newFunct = test.bind(this);
$(document).on('click', newFunct );
$(document).off('click', newFunct );
It should work fine
e.g: http://jsfiddle.net/508dr0hv/
Also - using bind is not recommended, its slow and not supported in some browsers.
rather than binding this to the event, send this as a parameter:
$("#DOM").on("click",{
'_this':this
},myFun);
myFun(e){
console.info(e.data._this);
$("#DOM").off("click",myFun);
}
Related
I would like to disable a certain function from running as an onclick event.
Here, I would like to disable myfunc1, not myfunc2. Actually I want to disable myfunc1 from the whole page, but anyway this is the only thing that I need.
I have no control over the page and I am using userscript or other script injection tools to achieve this.
What I've tried:
Redefining the function after the page has loaded: I've tried adding an event listener to an event DOMContentLoaded with function(){ myfunc1 = function(){}; }
This seems to be working, but in a fast computer with fast internet connection, sometimes it runs before the myfunc1 is defined (in an external js file that is synchronously loaded). Is there any way that I can guarantee that the function will be executed after myfunc1 is defined?
Is there any way that I can 'hijack' the onclick event to remove myfunc1 by its name?
You should use event listeners, and then you would be able to remove one with removeEventListener. If you can't alter the HTML source you will need something dirty like
function myfunc1() {
console.log('myfunc1');
}
function myfunc2() {
console.log('myfunc2');
}
var a = document.querySelector('a[onclick="myfunc1();myfunc2();"]');
a.setAttribute('onclick', 'myfunc2();');
Click me
Or maybe you prefer hijacking the function instead of the event handler:
function myfunc1() {
console.log('myfunc1');
}
function myfunc2() {
console.log('myfunc2');
}
var a = document.querySelector('a[onclick="myfunc1();myfunc2();"]');
var myfunc1_;
a.parentNode.addEventListener('click', function(e) { // Hijack
if(a.contains(e.target)) {
myfunc1_ = window.myfunc1;
window.myfunc1 = function(){};
}
}, true);
a.addEventListener('click', function(e) { // Restore
window.myfunc1 = myfunc1_;
myfunc1_ = undefined;
});
Click me
Another way this could be done is using Jquery and setting the onlick propery on the anchor tag to null. Then you could attach a click function with just myfunc2() attached.
$(document).ready(function () {
$("a").prop("onclick", null);
$("a").click(function(){
myfunc2();
});
});
function myfunc1() {
console.log('1');
}
function myfunc2() {
console.log('2');
}
<a class="test" href="#" onclick="myfunc1();myfunc2();">Example</a>
You can see the codepen here - http://codepen.io/anon/pen/BLBYpO
Perhaps you are into jQuery.
$(document).ready(function(){
var $btn = $('button[onclick*="funcOne()"]');
$btn.each(function(){
var newBtnClickAttr;
var $this = $(this);
var btnClickAttr = $this.attr("onclick");
newBtnClickAttr = btnClickAttr.replace(/funcOne\(\)\;/g, "");
$this.attr("onclick", newBtnClickAttr);
});
});
Where in the variable $btn gets all the button element with an onclick attribute that contains funcOne().
In your case, this would be the function you would like to remove on the attribute e.g., myfunc1();.
Now that you have selected all of the elements with that onclick function.
Loop them and get there current attribute value and remove the function name by replacing it with an empty string.
Now that you have the value which does not contain the function name that you have replace, you can now update the onclick attribute value with the value of newBtnClickAttr.
Check this Sample Fiddle
I want the events click and touchstart to trigger a function.
Of course this is simple with JQuery. $('#id').on('click touchstart', function{...});
But then once that event is triggered, I want that same handler to do something else when the events are triggered,
and then later, I want to go back to the original handling function.
It seems like there must be a cleaner way to do this than using $('#id').off('click touchstart'); and then re-applying the handler.
How should I be doing this?
You can create a counter variable in some construct in your javascript code that allows you to decide how you want to handle your event.
$(function() {
var trackClicks = (function() {
var clicks = true;
var getClicks = function() {
return clicks;
};
var eventClick = function() {
clicks = !clicks;
};
return {
getClicks: getClicks,
eventClicks: eventClicks
}
})();
$('#id').on('click touchstart', function {
if (trackClicks.getClicks()) {
handler1();
} else {
handler2();
}
trackClicks.eventClick();
});
function handler1() { //firsthandler};
function handler2() { //secondhandler};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
The way I would do this is by creating a couple of functions for the handler function to call based on certain flags. Sudo code would be something like this:
function beginning_action() {
...
}
function middle() {
...
}
var beginning_state = true;
$('#id').on('click touchstart', function{
if(beginning_state) {
beginning_action();
} else {
middle();
}
});
Then all you need to do is change the variable beginning_state to change which function is called. Of course you would give them better names that describe what they do and not when they do it.
Additionally, if you want the handler to call more than two functions you can change the beginning_state variable from a boolean to an int and check it's value to determine which function to call.
Good luck!
I want to call a function on the click event, my collegue defined the function as written below. Somehow I cannot access it, what is wrong?
function Start(data) {
this.move= function() {
....
};
$('.button').click(function(){
this.move();
});
}
this in a click function is the clicked element. Save a reference of the object in a variable outside the function and use it :
function Start(data) {
var self = this; //HERE
this.move= function() {
....
};
$('.button').click(function(){
self.move();
});
}
Here's an article that may give you more explanation about the above fix.
try this, you must remember reference to your main function.
function Start(data) {
var that = this;
this.move = function() {
....
};
$('.button').click(function(){
that.move();
});
}
Another way to keep the scope is to use jQuery's proxy()
$('.button').click($.proxy(this.move, this));
In an event handler bound with jQuery, this refers to the DOM element on which the handler was bound. See jQuery Event Basics.
You can override jQuery's this binding by using function#bind on the click handler:
function Start(data) {
this.move= function() {
....
};
$('.button').click(function(){
this.move();
}.bind(this));
}
Beware of browser support for function#bind -- if you target older browsers you'd need a polyfill or simply assign the value of this to another variable.
I'm trying to bind a hover event to some elements, walking through them with $.each, with the peculiarity that I want to pass a css classname as a parameter of the hover's handler functions, but it seems that the scope is not the one I'm expecting. I've tried to
$(document).ready(function () {
var $madewithLabels = $("#made-with .label");
// Binding
$madewithLabels.each(function (index) {
// get bootstrap css classname for the current element in the loop
var bsClass = getHoverClass($(this));
console.info("css class is: " + bsClass + " - " + typeof(bsClass));
$(this).hover(
function (bsClass) {
console.info(bsClass);
$(this).addClass(bsClass);
},
function (bsClass) {
console.info(bsClass);
$(this).removeClass(bsClass);
}
);
});
});
1st console.info: getHover() gets the right css class name (string) when the events are bound (on document ready)
2nd/3rd console.info: when hover's handler functions are executed bsClass is an object (I guess it's a jQuery one)
I've solved it this way:
$(document).ready(function () {
var $madewithLabels = $("#made-with .label");
// Binding
$madewithLabels.each(function (index) {
$(this).hover(
function () {
$(this).addClass(getHoverClass($(this)));
},
function () {
$(this).removeClass(getHoverClass($(this)));
}
);
});
});
But my questions are...
Is using $(this) the right solution?
Why when I pass a string variable to the handler functions I get an object when the function is called? is it because some type casting? is it because closure scope?
Thanks to the jQuery gurus answering!
What you're getting in the hover callback is an Event object, as mentioned by the docs:
handlerIn
Type: Function( Event eventObject )
A function to execute when the mouse pointer enters the element.
So in your first example change:
function (bsClass) {
To this:
function () {
So you keep using the original bsClass that you calculated before.
Sorry for how stupid this is going to sound. My JS vocabulary is terrible and I had absolutely no idea what to search for.
I'm using jQuery.
So I've got this code:
var example = {
open: function(element){
alert(element.text());
},
init: function(){
$("a").click(example.open);
}
};
$(document).ready(function(){example.init();)
So here's the problem: I want to pass an argument to example.open() when I click the "a" element. It doesn't seem like I can, though. In order for the example.open method to just…exist on page-load and not just run, it can't have parentheses. I think. So there's no way to pass it an argument.
So I guess my question is…how do you pass an argument to a function that can't have parentheses?
Thanks so much.
Insert another anonymous function:
var example = {
open: function(element){
alert(element.text());
},
init: function(){
$("a").click(function()
{
example.open($(this));
});
}
};
You can also try this version because jQuery set the function's context (this) to the DOM element:
var example = {
open: function(){
alert($(this).text());
},
init: function(){
$("button").click(example.open);
}
};
Since jQuery binds the HTML element that raised the event into the this variable, you just have to pass it as a regular parameter:
var example = {
open: function(element){
alert(element.text());
},
init: function(){
$("a").click(function() {
// jQuery binds "this" to the element that initiated the event
example.open(this);
});
}
}
$(document).ready(function(){example.init();)
You can pass the anchor through its own handler:
var example = {
open: function( element ){
alert(element.text());
},
init: function(){
$("a").on("click", function() {
example.open( $(this) );
});
}
};
$(document).ready(function() {
example.init();
});
I don't understand what you actually want to do;
however, I can give a try:
var example = {
open: function(event){
event.preventDefault();
alert($(event.target).text()+' : '+event.data.x);
},
init: function(){
$("a").bind('click',{x:10},example.open);
}
};
$(example.init);
demo:
http://jsfiddle.net/rahen/EM2g9/2/
Sorry, I misunderstood the question.
There are several ways to handle this:
Wrap the call in a function:
$('a').click( function(){ example.open( $(this) ) } );
Where $(this) can be replaced by your argument list
Call a different event creator function, which takes the arguments as a parameter:
$('a').bind( 'click', {yourvariable:yourvalue}, example.open );
Where open takes a parameter called event and you can access your variable through the event.data (in the above it'd be event.data.yourvariable)
Errors and Other Info
However your element.text() won't just work unless element is a jQuery object. So you can jQueryify the object before passing it to the function, or after it's received by the function:
jQuery the passed object:
function(){ example.open(this) } /* to */ function(){ example.open($(this)) }
jQuery the received object:
alert(element.text()); /* to */ alert($(element).text());
That said, when calling an object without parameters this will refer to the object in scope (that generated the event). So, really, if you don't need to pass extra parameters you can get away with something like:
var example = {
open: function(){ // no argument needed
alert($(this).text()); // this points to element being clicked
},
init: function(){
$("a").click(example.open);
}
};
$(document).ready(function(){
example.init();
}); // your ready function was missing closing brace '}'