I have an object that I want to pass to .fadeOut().
Before we get to that, here's how I can pass an object to .click():
this.$title.click({story: this}, function (event){
var story = event.data.story;
}
Simple enough.
Now I want to do something similar with .fadeOut:
this.$title.fadeOut("fast", {story: this}, function(){
var story = ???
});
Which doesn't work. But you get the idea? How can I pass this into the anon function?
I'm looking for the cleanest solution. Barring that, I'm looking for the solution that's most in line with what I've done with .click().
Thanks!
ASIDE: is there a cleaner way pass this into .click()?
This is rather a question about JS than about jQuery; you can do it like that:
var story = this
this.$title.click(function () {
/* story still available */
})
this.$title.fadeOut('fast', function () {
/* same here */
})
Or something more fancy (this also preserves the content of story at the moment of assignment even if it gets overwritten in the upper scope later on):
this.$title.click((function (story) {
return function () {
/* story is available */
/* this will be passed to $(...).click(...) */
}
})(this))
It seems fadeOut() doesnt have an overload like click() where you can pass eventData
.click( [eventData ], handler )
Therefore, make a preserve this in a closure and use inside the function
var story = this;
this.$title.fadeOut("fast", function(){
//story can be used here
});
Related
Say I had code like so:
function on(loc,type,func){
loc.addEventListener(type, function(e){
func(e);
});
}
If I called it like this:
on(document.getElementById('test'),"click",function(){
alert('You clicked!');
});
It would work, but I want to be able to call the on function like so:
document.getElementById('test').on('click', function(){
alert('You clicked!');
});
How can I make it able to be called like so?
As has been pointed out, the DocumentElement does not have an .on() method. Yet!
You can, however, add one by extending the prototype, adding a new property and making your function available on all Elements. This is quite easy (and I'll provide a trivial example in a moment), but it's also widely considered to be a bad practice. So before you try this out, understand that Javascript absolutely does make it possible...but that doesn't mean it's a good idea.
Now, that example:
Element.prototype.test = function() {
console.log("Successfully extended the prototype of a native object!");
}
document.getElementById("footer").test();
You cannot do this because the DocumentElement does not have a property (or allow you to create one (that I know of)) of your on function.
You could get away with doing something similar such as modifying your on function to handle the onlcick event for a given element. I haven't tested the below code but it should give you an idea:
function on (element) {
var obj = {
clickEvent : function () {
element.onclick = function () {
alert("you clicked");
}
}
};
return obj;
}
var theElement = document.getElementById("test");
on(theElement).clickEvent();
I'm writing an awesome IIFE and want this to be as easy as possible for my users who use it. So I was thinking since some of them don't know that to easily remove an eventlistener without it already being a function we can give that inline function a name
Example
document.addEventListener('click',function dood(){
//some function
},false);
document.removeEventListener('click',dood,false);
//instead of
function dood(){
//some function
}
document.addEventListener('click',dood,false);
document.removeEventListener('click',dood,false);
But since they shouldn't know the name exactly I was wondering if we could do
var k = "name_of_function";
document.addEventListener('click',function window[k](){
//the function
},false);
Though I know this does not work is there a way to do this? I'd like to make it so they can easily do this
object.cancel('name_of_function') //which will be the name of the instance
// they created earlier if they gave that instance a name
object={
cancel:function(nm){
document.removeEventListener(self.trigger,window[nm],false);
//self.trigger really is this.trigger which they assign as either scroll,click,mousemove,etc.
}
};
Any ideas? Or is this not possible at all?
usage is:
scrollex('element',{
max:500,
min:500,
pin:200,
offset:0.5,
name:'google',//this then would be used in multiple instances
});
scrollex.events //shows all events and their names
scrollex.listen('google'); //it'll console log all info for this event
scrollex.cancel('google');
I think you're on the right track. But you should not use window, and some local object instead. And dynamically naming function expressions (or whatever that function window[k](){} was supposed to mean) is impossible a pain - don't try this. Just let them stay anonymous, and reference them only via property names / variables.
var object = (function() {
var listeners = {
name_of_function: function dood(){…}
};
document.addEventListener('click', listeners.name_of_function, false);
return {
cancel: function(nm) {
document.removeEventListener('click', listeners[nm], false);
}
};
}());
// now, you can
object.cancel('name_of_function')
I have an occurence where I want to have a main js-file with one resize function and specific files that can add workload to the main file without changing the mainfile and manually calling functions.
Lets say I have an object literal
var App = {
resize: function(){
// Code should be executed here
},
addResize: function(){
// ?
}
}
and I want a function to add code to the resize function which dynamically adds workload to the resize function (which gets called on window resize):
App.addResize(function(){ ... });
The first thing that came to my mind is to store the anonymous functions from addResize to an array and iterating over it in the resize function, but that doesn't feel like doing a best-practice:
var App = {
resizeFunctions = [];
resize: function(){
// iterate over resizeFunctions and call each one
// here I define throttling/debouncing ONCE
},
addResize: function(fn){
this.resizeFunctions.push(fn);
}
}
window.onresize = App.resize();
App.addResize(fn1);
App.addResize(fn2);
Is there a better way?
as you are referring to one function, ie. a resize function, I assume that you are looking for function overloading:
Function overloading in Javascript - Best practices
http://ejohn.org/blog/javascript-method-overloading/
If you want to extend the functionality of a set of methods that are all related to a single parent-object into different child objects, I would look into prototypal inheritance.
It allows you to define re-define the parent methods for each of the child-objects.
Do you want to overwrite the existing function?
Then you can just do this:
App.addResize = function(){}
App.addResize(function(){ ... });
would pass the function to addResize as an attribute but not add it to it. You could do
App.addResize.newFunction = function(){ ... };
Where newFunction is the name of the function
You can treat your object literal as array.
App["resize"] = function(){
//Code goes here
}
__
Or
App.resize = function(){
//Code here
}
Both are equally good. These will update the definition of resize
If you want to add some new method, then too the same syntax will work.
App["myNewMethod"] = new function(){
//Code here
}
Edit after OP's comment
var oldFun = App["resize"]; // or may be store this in App itself
App["resize"] = function(){
//Pre-processing
// Now call original resize method
oldFun(); //If resize method used method argument then use oldFun.apply( this, arguments );
//Post processing
}
I'm doing this inside one of my Views:
render: function($options) {
...
this.collection.on('reset', _(function() {
this.render($options);
}).bind(this));
....
}
The problem is, whenever reset as well as the re-rendering has been triggered, a new reset binding will be created, resulting 2x, 4x, 8x, etc. times of re-rendering as it goes on.
It's a bit tricky to move the binding into the initialize section (which should solve this issue), however since it's not an option, is there any other solution available, like having Backbone checking if this event has been bound before, or something?
Moving your binding to initialize would be best but assuming that you have good reasons not to, you could just set a flag:
initialize: function() {
var _this = this;
this._finish_initializing = _.once(function($options) {
_this.collection.on('reset', function() {
_this.render($options);
});
});
//...
},
render: function($options) {
this._finish_initializing($options);
//...
}
There are lots of different ways to implement the flag, _.once just nicely hides the flag checking. You could also trigger an event in render have a listener that unbinds itself:
initialize: function() {
var finish_initializing = function($options) {
/* your binding goes here ... */
this.off('render', finish_initializing);
};
this.on('render', finish_initializing, this);
},
render: function($options) {
this.trigger('render', $options);
//...
}
That's the same logic really, just dressed up in different clothes. You could also use an explicit flag and an if in render or assign a function to this._finish in initialize and that function would delete this._finish.
like having Backbone checking if this event has been bound before, or something?
Sure..
!!this.collection._events["render"]
Backbone doesn't expose most of the API required to make it useful. That's alright, use it anyway.
First, define your event handler function as a named function
var self = this;
var onReset = function() {
self.render($options);
}
Then, defensively unbind the function each time render is called
this.collection.off('reset', onReset);
this.collection.on('reset', onReset);
I recently accomplished this using a javascript variable.
Outside of any functions, I declared:
var boundalready =0
Then, inside the function:
if (boundalready == 0){
boundalready = 1;
bind(this);
};
This worked for me pretty well.
I have a function which is a JQuery event handler. Because it is a JQuery event handler, it uses the this variable to refer to the object on which it is invoked (as is normal for that library).
Unfortunately, I need to manually call that method at this point. How do I make this inside the called function behave as if it were called from JQuery?
Example code:
function performAjaxRequest() {
//Function which builds AJAX request in terms of "this"
}
function buildForm(dialogOfForm) {
var inputItem;
dialogOfForm.html('...');
dialogOfForm.dialog('option', 'buttons', {
"Ok" : performAjaxRequest
});
inputItem = dialogOfForm.children(':not(label)');
//Redirect enter to submit the form
inputItem.keypress(function (e) {
if (e.which === 13) {
performAjaxRequest(); //Note that 'this' isn't the dialog box
//as performAjaxRequest expects here, it's
//the input element where the user pressed
//enter!
}
}
}
You can use the function's call method.
someFunction.call(objectToBeThis, argument1, argument2, andSoOnAndSoOn);
If dialog is the object that you need to be set to this then:
performAjaxRequest.apply(dialog, []);
// arguments (instead of []) might be even better
should do the trick.
Otherwise, in jQuery you can simply call the trigger method on the element that you want to have set to this
Say, for example, that you wanted to have a click event happen on a button and you need it to happen now. Simply call:
$("#my_button").trigger("click");
Your #my_button's click handler will be invoked, and this will be set to the #my_button element.
If you need to call a method with a different this ... say for example, with this referring to the jQuery object itself, then you will want to use call or apply on your function.
Chuck and meder have already given you examples of each ... but to have everything all in one place:
// Call
my_function.call(object_to_use_for_this, argument1, argument2, ... argumentN);
// Apply
my_function.apply(object_to_use_for_this, arguments_array);
SEE: A List Apart's Get Out of Binding Situations
Are you looking for..
functionRef.apply( objectContext, arguments);
You should of course learn to master call() and apply() as people have stated but a little helper never hurts...
In jQuery, there is $.proxy. In pure js, you can re-create that niftyness ;) with something like:
function proxyFn( fn , scope ){
return function(){
return fn.apply(scope,arguments);
}
}
Usage Examples:
var myFunctionThatUsesThis = function(A,B){
console.log(this,arguments); // {foo:'bar'},'a','b'
};
// setTimeout or do Ajax call or whatever you suppose loses "this"
var thisTarget = {foo: 'bar'};
setTimeout( proxyFn( myFunctionThatUsesThis, thisTarget) , 1000 , 'a', 'b' );
// or...
var contextForcedCallback = proxyFn( myAjaxCallback , someObjectToBeThis );
performAjaxRequest(myURL, someArgs, contextForcedCallback );
If you dont abuse it, it's a sure-fire tool to never loose the scope of "this".
use a closure
i.e assign this to that early on; then you can do what you like with it.
var that = this;