• 0

[JQuery] What's going on here?


Question

Hi guys, I've got the following algorithm and it's not doing what it should (at least in my mind).

Imagine that I have 6 elements each with 100% height of the window. This algorithm is supposed to change the height of each element to then display the desired one.

$(document).ready(function() {
	function tabs(y) {	
		if(y == 1)
		{
			$('#news_panel').css({'height':'100'});
		}
		if(y == 2)
		{

		}
		if(y == 3)
		{

		}
		if(y == 4)
		{

		}
		if(y == 5)
		{

		}
	}

	$('#quests').click('mousedown',tabs(1));
	$('#guides').click('mousedown',tabs(2));
	$('#tasks').click('mousedown',tabs(3));
	$('#links').click('mousedown',tabs(4));
	$('#options').click('mousedown',tabs(5));
});

Right now that code there is resizing the news_panel when the page loads, shouldn't it be waiting to be told when to do that by the if statement?

Link to comment
Share on other sites

6 answers to this question

Recommended Posts

  • 0

I *think* it's because of the way you've bound the click events. What I would normally do is something like;

$('#quests').click(function(){ tabs(1); });

I haven't tested it, but I'd expect it to work.

Link to comment
Share on other sites

  • 0

Did mine work? :laugh:

I can't remember the exact reasoning, but event handlers have to be anonymous functions (which can in turn call regular functions if they need to, as I did in my code). IIRC it has something to do with jquery passing an event object parameter to the anonymous function and I think that's probably why it was getting confused and running the code when it shouldn't have.

There's a slight difference between the mousedown and click events. The event is triggered in the former when the mouse button is clicked, but the latter event is triggered when the mouse button is released again. If you need to respond to mousedown rather than click., you could probably do something like;

$('#quests').mousedown(function(){ tabs(1); });

Link to comment
Share on other sites

  • 0

Mouldy Punk's code is correct indeed, but his explanation is not. :p

First of all, you can't pass 'mousedown' as first parameter to click(). You're probably confusing it with the bind() method, which accepts the event name as its first argument. In fact, that's exactly what happens when you use click() or mousedown(): they simply call bind() internally. The following examples are equivalent:

$('#quests').click(function() { tabs(1); });
$('#quests').bind('click', function() { tabs(1); });

There are a lot of similar synonym pairs in jQuery, some examples:

$('#elem').hover(handlerIn, handlerOut);
$('#elem').mouseenter(handlerIn).mouseleave(handlerOut);

$(document).ready(function() { alert("Hello"); });
$(function() { alert("Hello"); });

More importantly though, the reasoning why tabs(1) must be wrapped in an anonymous function is wrong. To understand why this is needed, you need to understand that bind() (or click/hover/...) accepts a function to use as event handler. The following is perfectly fine:

function foo() {
    alert("foo() was called");
}
$("#elem").click(foo);

As you would expect, this would call the function foo() when #elem is clicked. You can do the same with an anonymous function:

$("#elem").click(function() {
    alert("Anonymous handler was called");
});

Here, instead of giving the function a name and then referencing the function by its name, we create an anonymous function and immediately pass that as the handler parameter.

Now, what you want to do is bind an event handler and specify a parameter to be sent to that handler when the event is triggered. So you try:

function foo(x) {
    alert("foo() called with parameter "+x);
}
$("#elem").click(foo("bar"));

And it doesn't work. Instead of firing foo() when the event is triggered, foo() gets fired immediately and the click event isn't working at all. However, you can easily spot the mistake when you look at what's being passed to click().

When the JavaScript engine sees the line $("#elem").click(foo("bar"));, it sees that the function foo() is called with the argument "bar". It calls the function, executes it (thus popping up an alert) and retrieves the return value when it's done. Since there's no return statement inside foo(), it'll simply return void. Thus, void is passed as first argument to click(). This method can't do anything with a void handler, so it'll just ignore it and won't do anything.

As you can see, the error lies in the fact that you think you're passing a function, but you're actually passing void (or whatever foo() returns). The solution is to make sure you're actually passing a function to click()! There are multiple ways to do this, but probably the easiest way is to wrap it inside an anonymous function:

function foo(x) {
    alert("foo() called with parameter "+x);
}
$("#elem").click(function() { foo("bar"); });

Now let's see what's happening here.

The JavaScript engine once again has to parse the line with click(). This time however, it sees a valid function object function() { foo("bar"); } being passed as first argument and simply passes that as parameter to click(). This method sees that it has received a valid handler and binds it to the click event. Now, when the element is clicked, this function gets called. The body of the function gets executed, so the JavaScript engine runs the expression foo("bar");, thus calling foo() with the right argument at the right time.

So there you have it! ;)


I can't remember the exact reasoning, but event handlers have to be anonymous functions (which can in turn call regular functions if they need to, as I did in my code). IIRC it has something to do with jquery passing an event object parameter to the anonymous function and I think that's probably why it was getting confused and running the code when it shouldn't have.

You're correct about jQuery passing an event object to the passed event handler as its first parameter. An example from the jQuery documentation shows this:

$(document).ready(function() {
  $('#foo').bind('click', function(event) {
    alert('The mouse cursor is at ('
      + event.pageX + ', ' + event.pageY + ')');
  });
});

However, you don't have to use this parameter. JavaScript doesn't care that it's sending more parameters than your handler accepts, it'll just send them anyway but not name them (they're still accessible in arguments though).

Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.