I have the following code in JS:
if (Subs.Lsr!==null) {
Subs.Measure.Do("markLSRPosts",function() {
Subs.Lsr.Dom($ce);
});
}
Because this kind of code is inside my file multiple times I wanted to create a function for that:
function SingleMeasure(measureTitle, functionName) {
if (setting!==null) {
Subs.Measure.Do(measureTitle,function() {
functionName();
});
}
}
SingleMeasure(Subs.Lsr, "markLSRPosts", Subs.Lsr.Dom($ce));
Now my problem is that the function Subs.Lsr.Dom($ce) is called BEFORE my SingleMeasure()-Function is called (and so always, no matter what the condition of setting is).
I have to admit: This makes sense to me from coding logic. Nonetheless I wonder if there is another way to achieve what I want. (the method ...Dom() only being called when the setting-condition is met)
Now my problem is that the function Subs.Lsr.Dom($ce) is called BEFORE my SingleMeasure()
That's because you are calling it right here: Subs.Lsr.Dom($ce)
SingleMeasure(Subs.Lsr, "markLSRPosts", Subs.Lsr.Dom($ce));
You might pass it as an anonymous function:
SingleMeasure(Subs.Lsr, "markLSRPosts", function() {
Subs.Lsr.Dom($ce);
});
The callback will be invoked by your SingleMeasure function at a later stage.
Related
I am trying to create a basic javascript framework that you can pass different things into, including functions for it to execute later. Right now, I'm in a more simple testing phase, but I can't quite get the function calling to work. A piece of my code is here:
[My JS Fiddle][1]http://jsfiddle.net/mp243wm6/
My code has an object that holds different data, and I want to call the method later, but with data that is available at the time of creation. Here is a code snippet of the function that uses the function that is passed to the object:
clickMe : function() {
this.obj.click(function() {
this.func();
});
}
Any suggestions or things I should read are welcome.
The problem is that there're two different contexts:
clickMe : function() {
// here is one
this.obj.click(function() {
// here is another
this.func();
});
}
You can simple pass the function as parameter, like the following:
clickMe : function() {
this.obj.click($.proxy(this.func, this));
}
http://jsfiddle.net/mp243wm6/2/
The problem:
Considering your code in the JSFiddle, you have:
onClick : function() {
this.obj.click(function() {
this.func();
});
},
As noted, you have different contexts going on here.
Consider the snippet this.obj.click(function() { this.func(); }). The first this here is a reference to the framework.events object. The second this here is a reference to whatever will be this when this function get called. In the case of your JSFiddle, when this.func gets called, this is actually the DOM object that represents the <div id="test">TEST</div> node. Since it doesn't have a func function, calling func() on it causes:
Uncaught TypeError: undefined is not a function
You have to understand the following: you have to pass the correct this in which you want the function func to be called.
The solution:
A couple of ways to make it work as you would like:
1. with bind
this.obj.click(this.func.bind(this));
This way, you are telling: "call my this.func function, but make sure that it will be called using the this that I am passing as a parameter". Vanilla JS, no $.proxy stuff.
JSFiddle
2. with a copy of the reference to the actual function
onClick : function() {
var theFunctionReference = this.func;
this.obj.click(function() {
theFunctionReference();
});
},
This way, you will not rely on the value of this outside of the context of the framework.events object.
JSFiddle
The issue is that this is not bound to the correct object. I would suggest you look into Function.bind() because that creates a function with this pointing to the right thing.
I am working with a user control that has set of javascript functions that are called when an action is performed. This user control is used in a lot of places in the application.
When one of the inbuilt JS function completes execution, I need to fire a custom JS function on my page.
Is there a way for me to attach a function to be fired when another function completes execution? I don't want to update the inbuilt JS function to call this page JS function.
Hope this makes sense.
There are a couple design patterns you could use for this depending upon the specific code (which you have not shared) and what you can and cannot change:
Option 1: Add a callback to some existing code:
function mainFunction(callbackWhenDone) {
// do other stuff here
callbackWhenDone();
}
So, you can call this with:
mainFunction(myFunction);
Option 2: Wrap previous function:
obj.oldMethod = obj.mainFunction;
obj.mainFunction = function() {
this.oldMethod.apply(this, arguments);
// call your stuff here after executing the old method
myFunction();
}
So, now anytime someone does:
obj.mainFunction();
it will call the original method and then call your function.
You're basically trying to do callbacks. Since you're not mentioning what functions you're talking about (as in code), the best thing to do would be basically to wrap the function, -quick and dirty- and make it work with callbacks.
That way you can pass it a Lambda (Anonymous Function) and execute anything you want when it's done.
Updated to demonstrate how to add Callbacks:
function my_function($a, $callback) {
alert($a);
$callback();
}
my_function('argument', function() {
alert('Completed');
});
The ugliest and best solution is to monkey-patch the built-in function. Assume the built-in function is called "thirdParty":
// first, store a ref to the original
var copyOfThirdParty = thirdParty;
// then, redefine it
var thirdParty = function() {
// call the original first (passing any necessary args on through)
copyOfThirdParty.apply(this, arguments);
// then do whatever you want when it's done;
// custom code goes here
customFunction();
};
We've essentially created a modified version of the built-in function without ever touching the original version.
Since Javascript is highly dynamic you can modify the original function without modifying its source code:
function connect_after(before, after){
return function(){
before.apply(this, arguments);
after();
};
}
var original_function = function(){ console.log(1); }
original_function = connect_after(original_function, function(){ console.log(2); })
I'm having some trouble with JavaScript and the passing of a function as parameter of another function.
let's say we are inside a class and do something like that:
this.get('target').update(this.onSuccess, this.onFail);
'target' is a JavaScript-object that has a method called update()
I'm calling this method and pass tow methods of the caller-class along as parameters
inside that update-method some stuff happens and when it's done that method should either call the onSuccess-method or the onFail-method. this looks something like:
update: function(onSuccess, onFail) {
if(true) {
onSuccess();
} else {
onFail();
}
}
until now, everything works pretty fine! but inside those success/fail-methods, that are defined in the caller-class (the one that calls above update-method), I'm using a this-pointer:
onFail: function() {
alert('Error: ' + this.get('target').error);
}
that this-pointer causes some issues. it doesn't point to the class where the method initially was defined but to the 'target'-object.
what I need to do now is to update the this-pointer right before the onSuccess / onFail calls inside the 'target'-class to make the methods work again. but this doesn't work due to a 'invalid assignment left-hand side'-error.
what is the best practice for a scenario like that? any ideas? thx in advance!!!
cheers
You have two options when calling update():
javascript function call()
javascript function apply()
the main difference being how you pass parameters to it. But they both allow scope/context injection.
Your code should look something like this:
this.get('target').update.call(this, this.onSuccess, this.onFail);
You can create a function that "binds" a function to a certain object (using a closure) and than pass these bound functions to the handler:
function bind(obj, fun) {
return function() {
return fun.apply(obj, arguments);
};
};
update(bind(this, this.onSuccess), bind(this, this.onFail));
To redirect this, you need a bind() (or similar) method in the Function class, as found in almost all JavaScript libraries:
if(!Function.prototype.bind){
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
}
}
}
Now do something like this:
update: function(onSuccess, onFail) {
if(true) {
onSuccess.bind(this)();
} else {
onFail.bind(this)();
}
}
The mechanism is explained here: Binding Scope in JavaScript
I generally write code that looks like this (but with many more handlers).
$(document).ready(function() {
$("#next").click(function() {
doStuff();
});
$("#prev").click(function() {
doSomeOtherStuff();
});
$("#link").hover(function() {
doSomeTotallyOtherStuff();
});
});
Is this the best way of doing this? Should I do it differently? Paul Irish's presentation suggests it's a bad idea. Is that true?
We like to use the object literal pattern and named functions. I'd rewrite your example like this:
$(function() {
Example.somegrouping.init();
});
var Example.somegrouping = {
init: function() {
// set up listeners
$("#next").click(this.onNextClick);
$("#prev").click(this.onPrevClick);
$("#link").hover(this.onLinkHover);
},
onNextClick: function() {
// do some stuff
},
onPrevClick: function() {
// do some stuff
},
onLinkHover: function() {
// do some stuff
}
};
Why? Well, it makes it easier to reuse event handlers in other places without resorting to triggers. The naming of the function can help self-document your code. Testing/debugging is easier. The object literal only adds one entry to the global namespace, so there is little chance for collisions with other scripts your page might be using.
One reason that it's useful to define your functions the old boring way is that you get names to look at in stack traces.
$(function() {
function nextClickHandler() { ... };
$('#next-button').click(nextClickHandler);
});
It's not safe to use a function name in a function expression:
$('#next-button').click(function nextClickHandler() { // DO NOT DO THIS
});
which is sort-of unfortunate but there you go.
This should be fine as long you don't do it in a loop or some other code that runs more than once (i.e. a recurring function call). Otherwise there's not much difference between one anon function and one named function. it's when you have 100 identical anonymous functions that's a problem.
ex:
$("#someID").click(function(){})
is okay,
for (var i in somelistofIDs) {
$(i).click(function(){})
}
is not, because you've created 100 anonymous functions instead of one named function.
EDIT
of course, if you're wrapping a single function call in a closure, you're doing it wrong, you can just pass the function itself.
I have an onclick handler for an <a> element (actually, it's a jQuery-created handler, but that's not important). It looks like this:
function handleOnClick() {
if(confirm("Are you sure?")) {
return handleOnClickConfirmed();
}
return false;
}
From this function, the this object is accessable as the <a> element clicked. However, handleOnClickConfirmed's this is a Window element! I want handleOnClickConfirmed to have the same this as handleOnClick does. How would I do this?
(I know I can pass this as an argument to handleOnClickConfirmed, but some of my code already uses handleOnClickConfirmed and I don't want to have to rewrite those calls. Besides, I think using this looks cleaner.)
The following ought to do it:
function handleOnClick() {
if( confirm( "Sure?" ) ) {
return handleOnClickConfirmed.call( this );
}
return false;
}
The call() function attached to Function objects is designed to allow this; calling a function with a desired context. It's an extremely useful trick when setting up event handlers that call back into functions within other objects.
Rob's answer is the best answer for your problem, but I wanted to address something that you wrote in your original question:
I know I can pass this as an argument to handleOnClickConfirmed, but some of my code already uses handleOnClickConfirmed and I don't want to have to rewrite those calls.
JavaScript parameters are always optional, as far as the interpreter is concerned. For example if you have the function:
function MyFunction(paramA, paraB) {
// do nothing
}
All of these calls will execute without error:
MyFunction(1,2);
MyFunction(1);
MyFunction();
So you could modify handleOnClickConfirmed to accept what would essentially be an optional parameter. Like so:
function handleOnClickConfirmed(context) {
context = context || this;
// use context instead of 'this' through the rest of your code
}
Again, in this particular case, the call function is the best solution. But the technique I outlined above is a good one to have in your toolbox.