If I have the following code:
function Something() {
this.randomElement = $("#element");
}
Something.prototype = {
functionOne: function() {
console.log("hello");
},
functionTwo: function() {
this.randomElement.click(function(e) {
this.functionOne(); //this becomes pointed at randomElement
});
}
}
How can I write this in a clean way where I wouldn't have to use Something.prototype.functionOne() to replace this.functionOne() inside of functionTwo? Since the click event changes the value of this?
Because this is bound to the item that is clicked. You need to use bind
this.randomElement.click( this.functionOne.bind(this) );
or jQuery's proxy.
this.randomElement.click( $.proxy(this.functionOne, this) );
Related
I am moving some jquery functions into a javascript object to clean up some code. My problem is, when I put methods on my object's constructor, my event handlers don't seem to respond to events but respond fine if my handlers are helper methods and are outside of the object's constructor.
Here's my code that isn't working
function MyConstructor() {
this.init();
this.selectAllHandler();
}
MyConstructor.prototype = {
init: function() {
$(document).on('click', '#my_element', this.selectAllHandler);
},
selectAllHandler: function() {
// some code in here
}
}
When using this, my code does not error out and putting console.log's atop the function runs. But when I try to click on the thing to trigger the handler, it doesn't do anything.
But, if I build it as a constructor using a method outside of the object, it works fine. Like this
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
$(document).on('click', '#my_element', selectAllHandler);
}
}
function selectAllHandler() {
// code that works fine
}
what am I doing wrong that I cannot call the handlers inside the object's prototype?
edit
Here is my new code. The problem now, is $(this) seems to refer to the constructor and no longer refers to the element being clicked on.
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
$(document).on('click', '#my_element', this.selectAllHandler.bind(this));
},
selectAllHandler: function() {
var checkboxes = $('.prospect_select_box');
console.log($(this)); // => [MyConstructor]
if (!$(this).prop('checked')) {
console.log('here')
checkboxes.prop('checked', false);
$('#prospect-left-section').hide();
} else {
console.log('other here')
checkboxes.prop('checked', true);
$('#prospect-left-section').show();
}
}
}
You have two objects you are interested in: the constructed object, and the clicked element. The first you need to find the method selectAllHandler, the second to work with $(this) within that function. Obviously both of them cannot be this at the same time, so you'll need to reference one of them in a different way.
Here is how you could do that.
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
var that = this;
$(document).on('click', '#my_element', function () {
that.selectAllHandler.call(this);
});
},
selectAllHandler: function() {
$(this).text('clicked!');
}
}
new MyConstructor();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="my_element">click me</button>
Note how call is used to make sure the selectAllHandler will run with this set to what jQuery passed on as element.
If however, you need to also reference the constructed object with this inside setAllHandler, then do it the other way around, and use that as this, but reference the clicked element via the event object that is passed to the function:
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
var that = this;
$(document).on('click', '#my_element', this.selectAllHandler.bind(this));
},
selectAllHandler: function(e) {
var elem = e.target;
$(elem).text('clicked ' + this.other);
},
other: 'me!'
}
new MyConstructor();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="my_element">click me</button>
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.
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 '}'
I am trying to build a media playlist that can advance the credits, play the video and change the title on thumb-hover, end of video and on next/prev click. So I need to write some functions that can then be called together. So like this:
function showBox()
{
$(this).parents('.container').find('.box').show();
};
function hideBox()
{
$(this).parents('.container').find('.box').hide();
};
$('a').hover(
function()
{
showBox();
},
function()
{
hideBox();
}
);
The problem is that $(this) does not carry through to the functions from the .hover. How do I do this?
Per #patrickdw's answer, jQuery sets the scope of a callback for an event to the DOM element upon which the event was fired. For example, see the eventObject parameter in the documentation for the click() handler.
My original answer (below) is useful when you want to create a jQuery plug-in so that you may invoke your own custom methods on jQuery objects and have the jQuery object set as this during execution. However, it is not the correct and simple answer to the original question.
// Within a plug-in, `this` is already a jQuery object, not DOM reference
$.fn.showBox = function(){ this.parents('.container').find('.box').show(); };
$.fn.hideBox = function(){ this.parents('.container').find('.box').hide(); };
$('a').hover(
function(){ $(this).showBox() },
function(){ $(this).hideBox() }
);
Edit: Or, if (as suggested) you want to add only one name to the ~global jQuery method namespace:
$.fn.myBox = function(cmd){
this.closest('.container').find('.box')[cmd]();
};
$('a').hover(
function(){ $(this).myBox('show') },
function(){ $(this).myBox('hide') }
);
Or more generally:
$.fn.myBox = function(cmd){
switch(cmd){
case 'foo':
...
break;
case 'bar':
...
break;
}
return this;
};
For more information, see the jQuery Plugin Authoring Guide.
The this will carry through if you just do:
$('a').hover(showBox,hideBox);
EDIT: To address the question in the comment, this will work for any function you assign as an event handler. Doesn't matter if it is an anonymous function or a named one.
This:
$('a').click(function() {
alert( this.tagName );
});
...is the same as:
function alertMe() {
alert( this.tagName );
}
$('a').click( alertMe );
...or this:
function alertMe() {
alert( this.tagName );
}
$('a').bind('click', alertMe );
In Javascript you can use call() or apply() to execute a function and explicitly specify this for it:
$('a').hover(
function()
{
showBox.call(this);
},
function()
{
hideBox.call(this);
}
);
The first parameter given to call() specifies the object that this will refer to in the function. Any further parameters are used as parameters in the function call.
You need to modify your code to something like this:
function showBox(elem)
{
elem.parents('.container').find('.box').show();
};
function hideBox(elem)
{
elem.parents('.container').find('.box').hide();
};
$('a').hover(
function()
{
var $this = $(this);
showBox($this);
},
function()
{
var $this = $(this);
hideBox($this);
}
);
$('a').hover(function() {
$(this).closest('.container').find('.box').show();
}, function() {
$(this).closest('.container').find('.box').hide();
});
Add parameters to showBox and hideBox so that they can accept the element, and then call showBox($(this)) and hideBox($(this)).