jQuery Event handlers for Javascript functions - javascript

The question title is a bit obscure so let me explain.
A requirement that was only explained to me recently is the use of jQuery in my project. But it has been noted that my functions are fine as is and can be reused as long as they contain some jQuery.
So I'm exploring the world of event listeners for the first time (js side not in the HTML)
A standard Jquery onclick event:
referenceToElement.onclick = function () { alert('here'); };
One thing I notice is that the function doesn't actually have a name. Is there any clean way of doing something like:
referenceToElement.onclick = myOldJavascriptFunction();
function myOldJavascriptFunction()
{
//blahblahblah
}
Is this good practice or is there a better way to do it. Will this even work now that I think of it?

Even if the question is actually worth a downvote, since you could easily answer all those questions by searching, I'll give you a headsup.
That
referenceToElement.onclick = function () { alert('here'); };
is for sure no jQuery standard thing. It's pure Javascript, adding a property to a DOM reference, in this case an anonymous function. However, you basically asked two questions now.
can we give that anonymous function a name ? => YES
can we reference a function which is defined somewhere else ? => YES
To give it a name, we can just create a named function expression like this
referenceToElement.onclick = function myFunctionName() { alert('here'); };
To reference a function, we just pass in it's name
referenceToElement.onclick = myOldJavascriptFunction;
Finally, jQuery's syntax to add the same event listener would look like this:
$( referenceToElement ).click( myOldJavascriptFunction );

Yes, you were very nearly right:
referenceToElement.onclick = myOldJavascriptFunction;
Note the lack of parentheses. This passes a reference to the function to the onclick event. Also note that this is plain old JavaScript, not jQuery. The jQuery way of doing this is more like:
$(referenceToElement).click(myOldJavascriptFunction);

Your first example there is plain and normal javascript, nothing to do with jQuery at all. If you were using jQuery, the line would look like this:
$(referenceToElement).click(function () { ... });
But in any case, it seems like you question is about anonymous functions. You can assign the function to a variable name, or use a function declaration and still reference that function by name:
function myFunction () { ... }
$(referenceToElement).click(myFunction);

Related

Javascript, passing 'e' to new Function, scope

I have a function block which is dynamic and I need to call with either eval or new Function (preferably the latter). I want to pass in the event it was raised from
function MyFunc(e)
{
new Function("OtherFunc(e, 'abcde')");
}
I can't see how to do this, I have tried a few things such as bind(this), and with(this) but no joy. It's an unusual thing to want to do hence my confusion.
NB I can see it works with eval but new Function would be better if possible and I get the impression it should be, e.g.
How to use scope in JavaScript for Function constructor? (second answer)
Any suggestions? Thanks
(Added: Why I want to do this)
I'm using Kendo mobile buttons. I'm moving from this:
<button onclick="MyFunc(e)"/>
to this
<button data-click="Call" data-func="MyFunc(e)"/>
this is because onclick is not recommended with Kendo UI on iPhones
Don't use the function constructor. Really, really don't. It is eval by another name. Use a function declaration instead. That won't break scope or expect to be built up out of strings.
function MyTest(e) {
function callOtherFunc() {
OtherFunc(e, "abcde");
}
return callOtherFunc;
}
So basically, you have buttons right now with
onclick="MyFunc(e); OtherFunc('a')"
...and you want to change those to
data-click="Call" data-func="MyFunc(e); OtherFunc('a')"
...and you're trying to figure out how to write your Call function without any significant refactoring, continuing to use the strings as you have them now in the onclick.
I'm a bit confused by your use of e within onclick rather than event. As far as I'm aware, there's no e in-scope for onXyz handlers; the event is available as event, though. In the answer below, I've assumed event in onclick but e everywhere else; adjust as necessary.
Within those constraints, eval and new Function are indeed pretty much your only option. It's not more evil than onclick (which is also eval in disguise); eval used with strings you control isn't necessarily evil, it's just usually a last resort (kind of like with).
Based on the documentation, looks like your Call would look something like this:
function Call(e) {
var code = this.element.prop("data-func");
var f = new Function("e", code);
f.call(this, e);
}
That ends up running the code with this being the element that was clicked, and with e in scope to the code in the generated function.
I do not recommend this except perhaps as a temporary measure during proper refactoring, but within the constraints you've given, that's how I see it working. One reason I don't recommend it is that, as with onclick, all of your functions have to be globals (because other than the args you pass it, new Function only has access to globals), and globals are best avoided like the plague.
Live example (with some workaround for the fact I didn't include Kendo):
// Kendo calls the data-click function with this being something
// other than the element; but the element is available as `this.element`
function fakeKendo(e) {
Call.call({element: this}, e);
}
function Call(e) {
// (Using getAttribute instead of Kendo's prop here)
var code = this.element.getAttribute("data-func");
var f = new Function("e", code);
f.call(this, e);
}
function MyFunc(e) {
snippet.log("MyFunc: e.type = " + e.type);
}
function OtherFunc(arg) {
snippet.log("OtherFunc: arg is " + arg);
}
<p onclick="fakeKendo.call(this, event)" data-func="MyFunc(e); OtherFunc('a')">
Click me
</p>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Javascript callback functions differences

I would like to know the difference between 2 implementations of callback functions.
This:
$("#button").on('click', function () {
//do something
});
Versus having the function already defined.
$("#button").on('click', btnFunction);
function btnFunction() {
//do something
}
Are there any implications with one compared to another? Performance-wise is one faster?
The first uses an anonymous function and the second does not. There's no difference in both.
See:
Why do you need to invoke an anonymous function on the same line?
Some folks prefer the second form because it gives a function name when using the debugger and tracing, but there are ways to get the same functionality in the first form.
If you are attaching and removing the event handler based on changing conditions, the second form is much easier to maintain, however.
There's no difference at all, and there's no performance issue with neither one of them. The only difference is that in one of them you're defining the callback function as an anonymous function, this way you cannot reuse it.
The other way, where you define it else where and named it and then pass it as a callback, you're defining a function that you can later reuse in another part of your code.
For example: if you want to do something when the document is ready, and then do se exact same thing when some one press a button you can use something like this:
function getData() {
//do something
}
$(function() {
// Call the function once the DOM is ready
getData();
});
// Call the same function when the button is clicked
$("#refresh_button").on('click', getData);
In most cases the first one will be used, called Anonymous Functions
The second one will be used when the function is not only used inlined here, but also needs to be reused somewhere else.
But anyway it could be a personal preference.
The only real difference you could see is that stack trace (if an exception is thrown for example) will be better, i.e. easier to debug, when using the second one.
Just reuse-ability.
In the second case, you could call btnFunction() somewhere else if need be.

MOOTOOLS variable scope

I'm using mootools:
I can't figure out how to use a variable when using an addEvent.
I want to use a for next loop to set values in a loop:
for (x=0;x<num;x++){
var onclickText = 'function (){onclick="addPageMoveEvent('+x+'"); }';
$('pageNum'+x).addEvent('click', onclickText);
}
>
I've search forums but not found any help.
Any help would be great.
Thanks
The addEvent method in MooTools accepts two arguments:
myElement.addEvent(type, fn);
Arguments:
type - (string) The event name to monitor ('click', 'load', etc) without the prefix 'on'.
fn - (function) The function to execute.
It does not take a string and passing a string such as "myFunction()" or "function() { myFunction(); }" will not work.
Since you are inside a loop, and the variable x will share the environment, you need to wrap its value inside another closure. One way is to use an additional closure:
$("pagenum" + x).addEvent("click", (function(value) {
return function() { addPageMoveEvent(value); }
})(x));
See all questions on StackOverflow regarding this particular problem of creating closures within loops.
Also worth checking out is this MDC article - Creating closures in loops: A common mistake
Warning: this first example will not work! Read on for an explanation.
You are confusing onclick HTML syntax with the MooTools addEvent. Try
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', 'addPageMoveEvent('+x+');');
}
This is simpler and cleaner, but might still not do what you want. This code will call the function addPageMoveEvent every time the link is clicked... is that what you want?
Since MooTools doesn't allow the above method, you must use the following:
A programmatically more interesting and less hazardous way to do the same would be:
factory = function (x) { return function() { addPageMoveEvent(x); }; };
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', factory(x));
}
This uses a factory for creating closures that hold your values of x... rather complex code, but it's the purist way. It also avoids using the scary eval that occurs because you feed addEvent a string. (It seems that MooTools doesn't like the other option anyway.)
That a use case for mootools pass method.
for (x=0;x<num;x++){
$('pageNum'+x).addEvent('click', addPageMoveEvent.pass(x));
}
Pass internally creates a closure that holds x in the his scope, so when the click event is fired it has the right value cause its not the same from the for loop.

Javascript plugins design pattern like jQuery

Could someone write down a very simple basic example in javascript to conceptualize (and hopefully make me understand) how the jQuery plugin design pattern is done and how it works?
I'm not interested in how creating plugin for jQuery (so no jQuery code here at all).
I'm interested in a simple explanation (maybe with a bit of Javascript code) to explain how it is done the plugin concept.
Plz do not reply me to go and read jQuery code, I tried, but I it's too complex, otherwise I would have not post a question here.
Thanks!
jQuery has a library of functions stored in an internal object named fn. These are the ones that you can call on every jQuery object.
When you do $("div.someClass") you get a jQuery object containing all <div> elements of that class. Now you can do $("div.someClass").each( someFunction ) to apply someFunction to each of them. This means, that each() is one of the functions stored in fn (a built-in one in this case).
If you extend (add to) the internal fn object, then you automatically make available your custom function to the same syntax. Lets assume you have a function that logs all elements to the console, called log(). You could append this function to $.fn, and then use it as $("div.someClass").log().
Every function appended to the fn object will be called in such a way that inside the function body, the this keyword will point to the jQuery object you've used.
Common practice is to return this at the end of the custom function, so that method chaining does not break: $("div.someClass").log().each( someFunction ).
There are several ways to append functions to the $.fn object, some safer than others. A pretty safe one is to do:
jQuery.fn.extend({
foo: function() {
this.each( function() { console.log(this.tagName); } );
return this;
}
})
Tomalak already posted almost everything You need to know.
There is one last thing that helps jQuery do the trick with the this keyword.
it's amethod called apply()
var somefunction=function(){
alert(this.text);
}
var anObject={text:"hello"};
somefunction.apply(anObject);
//alert "hello" will happen
It really helps in creating abstractions so that framework/plugin users would just use this as intuition tells them, whatever there is inside Your code
It works, as many other js frameworks, using javascript prototype orientation.
For instance you can declare a simple function
var alertHelloWorld = function() {
alert('hello world');
}
And then tie it to an existing object (including DOM nodes)
document.doMyAlert = alertHelloWorld;
If you do this
document.doMyAlert();
The alertHelloWorld function will be executed
You can read more about javascript object prototyping here

How to change onClick handler dynamically?

I'm sure there are a million posts about this out there, but surprisingly I'm having trouble finding something.
I have a simple script where I want to set the onClick handler for an <A> link on initialization of the page.
When I run this I immediately get a 'foo' alert box where I expected to only get an alert when I click on the link.
What stupid thing am I doing wrong? (I've tried click= and onClick=)...
<script language="javascript">
function init(){
document.getElementById("foo").click = new function() { alert('foo'); };
}
</script>
<body onload="init()">
<a id="foo" href=#>Click to run foo</a>
</body>
Edit: I changed my accepted answer to a jQuery answer. The answer by 'Már Örlygsson' is technically the correct answer to my original question (click should be onclick and new should be removed) but I strongly discourage anyone from using 'document.getElementById(...) directly in their code - and to use jQuery instead.
Try:
document.getElementById("foo").onclick = function (){alert('foo');};
Use .onclick (all lowercase). Like so:
document.getElementById("foo").onclick = function () {
alert('foo'); // do your stuff
return false; // <-- to suppress the default link behaviour
};
Actually, you'll probably find yourself way better off using some good library (I recommend jQuery for several reasons) to get you up and running, and writing clean javascript.
Cross-browser (in)compatibilities are a right hell to deal with for anyone - let alone someone who's just starting.
jQuery:
$('#foo').click(function() { alert('foo'); });
Or if you don't want it to follow the link href:
$('#foo').click(function() { alert('foo'); return false; });
I tried more or less all of the other solutions the other day, but none of them worked for me until I tried this one:
var submitButton = document.getElementById('submitButton');
submitButton.setAttribute('onclick', 'alert("hello");');
As far as I can tell, it works perfectly.
If you want to pass variables from the current function, another way to do this is, for example:
document.getElementById("space1").onclick = new Function("lrgWithInfo('"+myVar+"')");
If you don't need to pass information from this function, it's just:
document.getElementById("space1").onclick = new Function("lrgWithInfo('13')");
OMG... It's not only a problem of "jQuery Library" and "getElementById".
Sure, jQuery helps us to put cross-browser problems aside, but using the traditional way without libraries can still work well, if you really understand JavaScript ENOUGH!!!
Both #Már Örlygsson and #Darryl Hein gave you good ALTARNATIVES(I'd say, they're just altarnatives, not anwsers), where the former used the traditional way, and the latter jQuery way. But do you really know the answer to your problem? What is wrong with your code?
First, .click is a jQuery way. If you want to use traditional way, use .onclick instead. Or I recommend you concentrating on learning to use jQuery only, in case of confusing. jQuery is a good tool to use without knowing DOM enough.
The second problem, also the critical one, new function(){} is a very bad syntax, or say it is a wrong syntax.
No matter whether you want to go with jQuery or without it, you need to clarify it.
There are 3 basic ways declaring function:
function name () {code}
... = function() {code} // known as anonymous function or function literal
... = new Function("code") // Function Object
Note that javascript is case-sensitive, so new function() is not a standard syntax of javascript. Browsers may misunderstand the meaning.
Thus your code can be modified using the second way as
= function(){alert();}
Or using the third way as
= new Function("alert();");
Elaborating on it, the second way works almost the same as the third way, and the second way is very common, while the third is rare. Both of your best answers use the second way.
However, the third way can do something that the second can't do, because of "runtime" and "compile time". I just hope you know new Function() can be useful sometimes. One day you meet problems using function(){}, don't forget new Function().
To understand more, you are recommended read << JavaScript: The Definitive Guide, 6th Edition >>, O'Reilly.
I agree that using jQuery is the best option. You should also avoid using body's onload function and use jQuery's ready function instead. As for the event listeners, they should be functions that take one argument:
document.getElementById("foo").onclick = function (event){alert('foo');};
or in jQuery:
$('#foo').click(function(event) { alert('foo'); }
Here is the YUI counterpart to the jQuery posts above.
<script>
YAHOO.util.Event.onDOMReady(function() {
document.getElementById("foo").onclick = function (){alert('foo');};
});
</script>
I think you want to use jQuery's .bind and .unBind methods. In my testing, changing the click event using .click and .onclick actually called the newly assigned event, resulting in a never-ending loop.
For example, if the events you are toggling between are hide() and unHide(), and clicking one switches the click event to the other, you would end up in a continuous loop. A better way would be to do this:
$(element).unbind().bind( 'click' , function(){ alert('!') } );
Nobody addressed the actual problem which was happening, to explain why the alert was issued.
This code: document.getElementById("foo").click = new function() { alert('foo'); }; assigns the click property of the #foo element to an empty object. The anonymous function in here is meant to initialize the object. I like to think of this type of function as a constructor. You put the alert in there, so it gets called because the function gets called immediately.
See this question.
The YUI example above should really be:
<script>
YAHOO.util.Event.onDOMReady(function() {
Dom.get("foo").onclick = function (){alert('foo');};
});
</script>

Categories