I am working on a project which involves the ExtJS library and I came upon this piece of code which did not make sense (but it works). Please help :(.
TreePanel.on('click', showDocumentFromTree);
function showDocumentFromTree(node) {
if (TreePanel.getSelectionModel().isSelected(node)) {
dataStore.baseParams = {
node : node.id,
limit : 10
}
dataStore.load({
params : {
start : 0
}
});
}
};
So the function definition for "showDocumentFromTree" has a parameter called "node" but when the code calls it, it did not pass in anything. Also, the object "node" is not a global (as far as I know).
So I'm confused on how that works? Is this some magic that Javascript has?
Also, when I do a console.debug to print "node" it has stuff in it. (console.debug for FireBug)
Thank you for your time,
J
When the code is doing `TreePanel.on('click', showDocumentFromTree)', it isn't calling showDocumentFromTree, it's passing the function showDocumentFromTree as an argument. It will then be called later, by the onclick event handler that it's being set up for, and it will be passed its node argument then.
The first line binds the showDocumentFromTree function to the click event. What is passed to TreePanel.on is a reference to the showDocumentFromTree function, not the call itself.
When an event fires, the bound function(s) will be called, with the triggering object as the first parameter. In this case, it will be the DOM node that was clicked.
To illustrate, the first line can be rewritten to:
TreePanel.on('click', function(node) {
showDocumentFromTree(node);
});
OK, maybe this is not much clearer, but you can see that it actually passes a function as argument to the on method, rather than calling the method itself.
TreePanel is a class/component in Extjs. In your first line:
TreePanel.on('click', showDocumentFromTree);
You are assigning a click handler to the TreePanel class. Meaning, whenever the TreePanel is clicked, it will call your showDocumentFromTree function. Part of the Click Event for the TreePanel is to pass the TreeNode that initiated, or was the item, that "caused" the click event.
To see how this functionality works, look at the Ext.tree.TreeEventModel class specifically the initEvents, delegateClick, and onNodeClick functions.
In this case, the parameter to showDocumentFromTree is a magic parameter that is supplied by the browser when the user clicks on the element to which the action is attached. In this case, node will refer to the TreePanel. Javascript - The this keyword explains more detail about this mechanism. It is probably more common to use the parameter name this than node as in your example.
Wthout repeating what other posters have said about the browser supplying the arguments to the function, I wanted to make a general note about javaScript as a language. JavaScript, unlike languages like C++ and Java, does NOT respect parameters defined in the function signature. This means you can have a function like:
function doSomething(myParam){
... Does Some Stuff
}
Then call it in any manner below:
doSomething();
doSomething(foo);
doSomething(foo, bar);
doSomething(foo, bar, baz);
etc..
If it is called without parameters defined in the signature, the missing parameters will be undefined. Extra parameters can only be accessed by the args array that all functions have.
I know this wasn't specific to your question but I thought it might be good for context and general interest.
Related
I am writing a small library that will take care of adding and removing events. I am simply attempting to pass the parameters of a method to jQuery on.
Is there any reason that I should not be able to do this?
# within some object
...
on: (el, args...) ->
$(el).on.apply(this, args)
The way I am using this may not be correct, but I don't believe it is the problem.
Which would then be called like so:
SomeObj.on('#hi', 'click'
-> console.log('clicked element')
)
I get the error Uncaught TypeError: elem.each is not a function
For some reason this is totally stumping me.
The problem is the wrong usage of this, despite your assumption.
The issue is that when you call a member function ("method"), it usually operates on some object, it's "context". Invoking a function via apply, call or through bind doesn't have the context passed in automatically because that gets lost when you access the properties of the function (apply in this case). In order to overcome this, it off required to set the relevant this attribute. In your case, this means passing the $(el) object to the apply() function.
I am pretty new in JavaScript and JQuery and I have the following doubt.
I know that if I open the FireBug console typing window I see the content of the global object that in a JavaScript application that run into a browser is the current browser tab (the window).
Ok, so in this global object I can see all the global variables and all the global functions (the variables and the functions that are not defined inside another function).
So I have a page in which I link my .js file.
This file will contain some pure JavaScript function like this:
function myFunction() {
.................................
.................................
.................................
}
And so I will see the myFunction function as a field of the window global object because this function is global (it is not defined inside another function). This is perfectly clear to me.
So, into the .js file linked inside my page I also have something like this:
$(document).ready(function() {
$("#myButton").click(function() {
............................................
............................................
DO SOMETHING WHEN THE BUTTON HAVING id="myButton" IS CLICKED
............................................
............................................
});
});
So, this is a JQuery code and it should work in this way (correct me if I am doing wrong assertion).
There is the $ that is the JQuery objet (or what is it?).
On this JQuery object I call the ready() function that is the function that perform its inner callback function when the DOM is completly rendered.
So the inner callback function contain the:
$("#myButton").click(function() {...DO SOMETHING...});
the select a button having id="myButton" and add to it the click event listerner that itself define an inner callback function that is performed when the button is clicked.
Is it true?
Ok...so I think that all these stuff is not direcctly in the global object because it is not directly defined into my .js file but have to be in some memory space dedicate to JQuery.
So looking inside the window object inside the FireBug console I found two objects:
$: that I think is the JQuery object...so I think that my previous custom JQuery function have to be here but I can't find it.
JQuery: that is another object that is inside the window global object.
So, my doubt is: when, inside the ready() function I declare something like
$("#myButton").click(function() {...DO SOMETHING...});
where I can find the definition of the function() {...DO SOMETHING...} inside some object defined inside the window global object? Can I find it? Or am I missing something?
jQuery stores its event-related data in a data object events applied to each element. You can use $._data() to grab this info:
$._data($('#myButton')[0], 'events')
or
$._data(document.getElementById('myButton'), 'events')
To get the callback function that you applied for your button's click listener, you can simply grab the handler. For example:
$("#myButton").click(function () { console.log('clicked'); });
var eventsInfo = $._data(document.getElementById('myButton'), 'events');
console.log(eventsInfo.click[0].handler);
The above should print out "function () { console.log('clicked'); }".
Keep in mind that there is no public documentation available for $._data(), although it is a neat thing to know!
The following blog post mentions $._data() when jQuery v1.8 was released but does warn about this:
Note that this is not a supported public interface; the actual data structures may change incompatibly from version to version.
That was back in 2012. To this day, it seems to be working fine with the latest 1.x and 2.x versions, so I don't see this going away anytime soon.
This is an anonymous function, basically a piece of unique code that you don't really want to write a named function for.
It's a one-time use-case or rather it's used to bind custom click events without littering the global object with variables.
What an anonymous function does is the exact opposite of what you are asking since you can't find it in the global object (anonymous function).
.click is a function defined in $.fn and since $ is part of the window object you could traverse there to find click e.g. window.$.fn.click would be the path to the source of $(...).click(func...) but an anonymous function is a function that gets set and then forgotten (more or less).
After all, you're not giving it a name so there is no reference it can point to which is exactly what this is.
If you use a named function as an argument to another function it's called a callback function
An anonymous function is basically a nameless callback function, a callback function is a normal function that can be passed to other functions as a callable argument - this normal function will then internally use .call() or .apply() to execute the supplied callback which is what jQuery for instance does when you bind a click
The good thing here is that you're not missing anything at all, as a matter of fact - you're asking the right question because this will look like magic if you're just starting out but once you get the hang of it it's easy to understand and use (and misuse so be careful!)
If you'd like to know how this construction works you could always build your own function that accepts a callback / anonymous function e.g.
function result_based_on_callback(a, b, fn) {
fn.call(null, a, b);
}
The above function takes two parameters and a function, it will call the function and supply the two parameters to it (the null is the context of this which is a different kind of question :))
If we were to use the above construct to do a calculation we could do so like this:
console.log(result_based_on_callback(1, 2, function(a, b) { return a + b; }));
This would return 3, you can also do this with a normal function that would otherwise take two numbers and add them - it works the same except for just passing in the function name rather than the body
like this:
function do_add(a, b) {
return a + b;
}
console.log(result_based_on_callback(1, 2, do_add));
Which will do the exact same.
I hope this allows you to understand a bit of how this works, good luck!
bunny.mousedown = function(mouseData){
text.setText(mouseData.global.x);
}
The 'setText' part gets called when someone presses on the bunny sprite. I'm using PIXIjs.
Hello, I'm new to JS and having a bit of a hard time understanding this code. As I understand, everything in JS is an object, including functions. In other languages that I've had experience with, you'd just use event listeners with this kind of thing.
Mousedown is a callback function, or so it says in the documentation. I think I understand what's a callback function. But, I'm confused at how it's implemented in the code above.
function display(s , callb){
alert(s);
callb(1 , 2);
}
function add(q, r){
alert((q + r).toString());
}
display("amidoindisrite?", add);
callb would be the callback function, I think... But, anyway, I don't understand how the code on the very top gets executed/called. Anyone have any ideas? What would be the equivalent in Java or Python if there is one? Thanks.
In your second example, callb is a pointer to a function, or the function definition if you like. If you apply the parentheses after it, it executes the function with the parameters provided (if any, integers 1 and 2 in this case). Other ways to execute a callback are the call() and apply() methods.
In the first example, the mousedown property expects a value that is a callback, i.e. the function definition. This example defines a function that assigned to this mousedown property. When the mousedown event is triggered for the bunny object, the mousedown property is executed (using parentheses, call() or apply(), that would depend upon the Pixjs library). That property being the function defined, the text.setText method is run.
I hope that clarifies it.
Just a simple question. In my current understanding, the two following chunks of code are identical except one is enclosed in a function. Why does it work with method 1, but not method 2? What is the difference?
Method 1:
// Reset button
$('.reset').button({
icons: {primary: 'ui-icon-closethick'}
}).click(function(){groupList.change()});
Method 2:
// Reset button
$('.reset').button({
icons: {primary: 'ui-icon-closethick'}
}).click(groupList.change);
EDIT: JSFiddle: http://jsfiddle.net/B8YEa/2/ - Note how clicking "Two" throws the error Uncaught TypeError: Object #<HTMLButtonElement> has no method 'on' and "One" is just fine, as well as the actual changing of the select
The difference is that the first code calls the function as a method of the object, while the second code calls the function as an independent function.
In the first case, this will reference the groupList object inside the function, while in the second case, this will reference the global window object.
If you call a function specifying it as an object member, e.g. obj.method();, it will be called as a method. If you get the reference to the function and call it, e.g. var m = obj.method; m();, then the method is't connected to the object any more.
Also, as Thilo pointed out, the first code will look up the method each time the event happens, while the second code will look up the method once when the event is bound.
If groupList.change does not exist yet, but is defined later (but before the user clicks), then there is a difference. Same if it gets re-defined later.
The first code resolves groupList.change when the click happens.
The second code resolves groupList.change immediately.
I was just curious if I could pass a function as a variable. For example:
I have a function
$('#validate').makeFloat({x:671,y:70,limitY:700});
I would like to do something like this:
$('#validate').makeFloat({x:function(){ return $("#tabs").offset().left+$("#tabs").width();},y:70,limitY:700});
This does not work, but ideally every time the variable was accessed it would compute the new value. So if the window was resized it would automatically adjust as opposed to a variable passed in being static. I realize I can implement this directly inside the function\widget, but I was wondering if there was some way to do something like the above.
The concept of this is independent of the plugin. I am talking about the function being "cast" as a variable.
Yes, you can pass an object which will invoke some function when its property is read (this is called a getter), but it is not cross-browser compatible. For example, this will (probably) work in IE9:
var o = {y:70, limitY:700};
Object.defineProperty(o, 'x', {get: function() {return 671;}});
$('#validate').makeFloat(o);
There are other syntaxes for other browsers such as __defineGetter__ for Firefox, and some browsers don't have this functionality at all. So it is practically useless unless you can fully control the environment where your code runs.
This won't work unless x is invoked (obj.x(), instead of just obj.x).
To make it work, the makeFloat() code must check the type of x, and if it's a function, invoke it.
I see what you're trying to do, but it won't work. Why? makeFloat expects the value to be non-function type. It probably uses that value directly. To actually execute the function, makeFloat needs to do x() or even x.call(...) or x.apply(...), which it most certainly isn't doing.
To answer your other question i.e., can you pass functions as variables, the answer is yes. In fact, this is the way callbacks and closures are handled in Javascript. For example, in jQuery when you bind an event handler you are passing in a function as a parameter:
jQuery("#myInputId").click(function() {
...
...
});
Another way that parameters are passed in are as object attributes, for example in jQuery.ajax:
jQuery.ajax({
...
success: function(data) {
},
...
});
In both cases, click and ajax both understand and expect the parameter to be a function and not just a regular variable. For example, assuming you had an object that maintained a list of integers and you had a method called addElement(int), which expected an int parameter, you wouldn't pass in a String. It works the same way in Javascript, except for the fact that the language is not strongly typed. This is why you don't really get a type-mismatch error unless the function explicitly checks the type and throws an exception. This is generally a good practice in such language; I try to do this in the Javascript code that I write.
I've done this with string variables. You'll need to exploit the toString function.
function RefString(fn) { this.toString = function() { return String(fn()); }; }
You can use it like so:
$("#someDiv").somePlugin({optionValue: new RefString(MyFunc), ... });
function MyFunc() {
return new Date().getYear().toString();
}
It works by setting optionValue to a new OBJECT, not necessarily a function. Then anything that reads this object will ask for a value, which by default is the result of the toString function. We simply override the default behavior by executing a function that is specified when the object is constructed.
I'm not sure how it will work for EVERY plugin, but it works when a string or number is expected.
How do you mean "doesn't work"?
It looks like it should compile and run. But what happens is it executes the function and sets the value no different than if you used a constant, or called a function that wasn't inline.
What you need to do is put this line of code in an event that fires when the window is re-sized.
It looks like makeFloat is from a jQuery plugin - are you sure that the plugin is aware that 'x' can be a function and will execute it properly? From the jQuery site, it looks like it only is able to comprehend a number value or 'current' as a string, not a function.
You can pass functions as variables, yes - but that's not actually what you're asking.
What it looks like your asking is "can I set a DOM property to the result of an expression?" to which the answer is "no". (Note - not outside of browser-specific behavior such as IE's CSS Expressions - which have been deprecated in IE8 anyway)
You'll need to bind an event handler to window.onresize and use a function to update the sizing yourself.
In order for a function to be executed from a variable, it has to be called, like so:
$.option.callback.call();
Where option is the containing variable, callback is the function and call executes the function.
It's not like you don't have options though. You can set it up so that the returned value of that function is executed from the line itself. Or you can set it up in the alternative manner that you described.
You need to invoke that function so that it returns the actual value you're looking for. So you're not actually passing in a function, you're invoking it and it's immediately returning a value. For example:
$('#validate').makeFloat({
x:function(){
return $("#tabs").offset().left+$("#tabs").width();
}(),
y:70,
limitY:700
});
Notice the extra () after the function call. This invokes the function immediately, thus returning the value you're looking for.
Note that x doesn't "compute new value" when is accessed (read), but when the function is called, i.e. x(). As Chad mentioned, this is how you can automatically execute a function when windows is resized:
$(window).resize(function() {
// do something
});
[Update] After re-reading your question, I think you may be thinking overcomplicated – isn't this what you are looking for?
$('#validate').makeFloat({
x: $("#tabs").offset().left + $("#tabs").width(),
y: 70,
limitY: 700
});