Say I have a javascript function for a hover event like this:
hoverFunc = function (HoverElement, AnimatedElement) {
HoverElement.on({
mouseenter: function () {
AnimatedElement.hide();
}
});
}
The tricky part is I want to keep AnimatedElement dynamic, and be able to use it as a reference of HoverElement's "this".
Here's an example of how I'd want AnimatedElement to function:
hoverFunc = function (HoverElement, AnimatedElement) {
HoverElement.on({
mouseenter: function () {
$(this).find("img").hide(); //this being a reference to HoverElement
}
});
}
So I'd like AnimatedElement to be able to be a "this" reference to HoverElement. I've tried writing it like this:
hoverFunc($("div"), $(this).find("img"));
But obviously the "this" will not reference the first parameter. Is there a way to achieve this? Thanks
instead of this use event.target and pass event in mouseenter function call
mouseenter: function (event) {
$(event.target).find("img").hide(); //this being a reference to HoverElement
}
Use bind() to do this
hoverFunc = function (HoverElement, AnimatedElement) {
HoverElement.on({
mouseenter: function () {
$(this).find("img").hide(); //this being a reference to HoverElement
}.bind(HoverElement)
});
}
fnc.bind() Description
From your example,
hoverFunc = function (HoverElement, AnimatedElement) {
HoverElement.on({
mouseenter: function () {
$(this).find("img").hide(); //this being a reference to HoverElement
}
});
}
Here this withing mouseenter event is actually HoverElement's this. As you're binding the mouseenter on HoverElement, so withing event callback this is actually HoverElement.
DEMO
Related
I have different "Profiles" in a Json-File. In an index.html different profile cards are shown and filled with the information of the Json-File. When you click on a Profil (Profil-Card) a detailed profile.html will be loaded and the function initateProfile will be executed.
$(document).on("click", ".profile-card", function () {
$('#page-content').load("sections/profile.html", function () {
initiateProfile($(this).data("profileid"));
});
});
I want to transmit the content of the profileid-class, which is the index for the Json-File.
function initiateProfile(id) {
var profile_data;
$.getJSON('data/profiles.json', function (data) {
profile_data = data[id];
$('.trn-name').text(profile_data.name);
$('.trn-studies').text(profile_data.studies);
$('.trn-stage').text(profile_data.stage);
});
}
Unfortunatly the id-variable is undefined. So the function can't get the information of the Json-File. What's the problem?
Thx
The issue is because this within the load() callback handler function is not the element which raised the event. It runs under a different scope. To fix this you need to save the element reference to a variable in the scope of the click handler, and use that within the callback, something like this:
$(document).on("click", ".profile-card", function () {
var profileId = $(this).data('profileid');
$('#page-content').load("sections/profile.html", function () {
initiateProfile(profileId);
});
});
Assuming that the data-profileid attribute is defined on the element which has the class .profile-card:
Your problem is this.
$(document).on("click", ".profile-card", function () {
$('#page-content').load("sections/profile.html", function () {
initiateProfile($(this).data("profileid")); // "this" points to the element with id "page-content"
});
});
One solution would be to use event.currentTarget:
$(document).on("click", ".profile-card", function (event) {
$('#page-content').load("sections/profile.html", function () {
initiateProfile($(event.currentTarget).data("profileid"));
});
});
I am trying to understand the difference between these two callback methods and how they handle the $(this) context.
Working Example
$("#container").on("click",".button", function() {
$(this).text("foo");
});
This process works just fine. However, if I want to do a different approach, I lose the context of the event.
Non-Working Example
bindAnEventToAnElement: function(theElement, theEvent, theFunctions) {
$("body").on(theEvent, theElement, function() {
theFunctions();
});
}
bindAnEventToAnElement(".button", "click", function() {
$(this).text("foo");
});
The latter produces an undefined error. Is there a way I can handle callbacks like this while retaining the context of the event?
Fiddle
http://jsfiddle.net/szrjt6ta/
AFAIK, jquery's this in that callback function refers to the event.currentTarget value. So, you should also pass the event object and do something like this:
$("#container").on("click", ".button", function () {
$(this).text("foo");
});
theApp = {
bindAnEventToAnElement: function (theElement, theEvent, theFunctions) {
$("body").on(theEvent, theElement, function (e) {
theFunctions.apply(this /* or e.currentTarget */, arguments);
});
}
}
theApp.bindAnEventToAnElement(".button-two", "click", function () {
$(this).text("foo");
});
Working Fiddle
If I try to explain the problem, jquery is binding the callback function to pass this as e.currentTarget. But you are passing an another callback function inside that callback function whose scope will not be its parent callback function but will be the window. So, you need to again bind the this to the wrapped function, which you can do using apply or call.
You have to manually bind the context to the function in order to have this valorized inside your callback:
$("body").on(theEvent, theElement, function() {
theFunctions.apply(this);
});
example http://jsfiddle.net/szrjt6ta/1/
Find more about apply() here
you can pass the event, then use $(e.target)
https://jsfiddle.net/szrjt6ta/3/
Use .call(this) The call() method calls a function with a given this value and arguments provided individually.
Note: While the syntax of this function is almost identical to that of
apply(), the fundamental difference is that call() accepts an argument
list, while apply() accepts a single array of arguments.
$("#container").on("click",".button", function() {
$(this).text("foo");
});
theApp = {
bindAnEventToAnElement: function(theEvent, theElement, theFunctions) {
$("body").on(theEvent, theElement, function() {
theFunctions.call(this);
});
}
}
theApp.bindAnEventToAnElement("click", ".button-two", function() {
$(this).text("fooe");
});
Fiddle
Change the event handler attachment from
$("body").on(theEvent, theElement, function() {theFunctions();});
to
$("body " + theElement).on(theEvent, theFunctions);
Like this:
HTML:
<div id="container">
<a class="button">Button</a><br />
<a class="button-two">Button Binded</a>
</div>
JQuery:
$("#container").on("click",".button", function() {
$(this).text("foo");
});
theApp = {
bindAnEventToAnElement: function(theElement, theEvent, theFunctions) {
$("body " + theElement).on(theEvent, theFunctions);
}
}
theApp.bindAnEventToAnElement(".button-two", "click", function() {
$(this).text("foo");
});
Fiddle: https://jsfiddle.net/szrjt6ta/10/
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);
}
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.
$('#start') executes the function myFunction() and $('#stop') end it. How do I stop myFunction() from executing?
function myFunction() {
$(document).mousemove(function(e) {
$('#field').html(e.pageY)
});
}
$('#start').click(function() {
myFunction();
});
$('#stop').click(function() {
//stop myFunction
});
As Daniel pointed out, you actually want to unbind the event handler. You can use unbind for this:
$('#stop').click(function() {
$(document).unbind('mousemove');
});
But this will also remove all other mousemove event handlers, that might be attached by other plugins or similar (I mean, you attach to the document element not a "custom" element, so it can be that other JavaScript code also binds handlers to this element).
To prevent this, you can use event namespaces. You would attach the listener with:
function myFunction() {
$(document).bind('mousemove.namespace', function(e) {
$('#field').html(e.pageY);
});
}
and unbind:
$('#stop').click(function() {
$(document).unbind('mousemove.namespace');
});
This would only remove your specific handler.
You want to use the jQuery bind and unbind methods. For example:
function myFunction() {
$(document).mousemove(function(e) {
$('#field').html(e.pageY)
});
}
$('#start').bind('click.myFunction', function() {
myFunction();
});
$('#stop').bind('click', function() {
$('#start').unbind('click.myFunction');
});
You're not stopping the function from executing. Your myFunction() simply attaches a callback to an event listener, which is called whenever the mouse is moved on the document. The callback function is invoked and is terminated immediately.
You'd simply want to unbind the callback from the event listener. Check out the other answers for concrete examples.
A better way would be to use bind and unbind, like so:
function myFunction() {
$(document).mousemove(function(e) {
$('#field').html(e.pageY)
});
}
$('#start').bind('click', myFunction);
$('#stop').click(function() {
$('#start').unbind('click', myFunction);
});