Skip to main content
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Justin Hinden
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Justin Hinden

You Cannot Bind The Submit Event To Objects Using jQuery

By
Published in Comments (22)

One of the coolest things about jQuery is that you can both bind and trigger events on non-DOM-node objects. However, over the weekend, while I was working on my SRCHR submission - a client-only, YQL-powered search engine - I found out that this technique does not work with the "submit" event in IE. If I look at the line of code in the jQuery core library that is erroring, it appears to be part of the new "submit propagation" functionality, which I think is being used for live-style submit handling.

To see this in action, take a look at this small demo. In the following code, I am going to be instantiating a controller object for a given paragraph. This component, as a whole, will announce a "submit" event when the user double-clicks on the associated paragraph.

<!DOCTYPE HTML>
<html>
<head>
	<title>Binding The Submit Event On Objects In jQuery</title>
	<script type="text/javascript" src="jquery-1.4.2.js"></script>
	<script type="text/javascript">

		// I am a tiny class to control a paragraph.
		function ParaController( target ){
			var self = this;

			// Keep the target reference as the UI aspect of this
			// controller instance.
			this.ui = target;

			// Bind the double-click event to the UI aspect.
			this.ui.dblclick(
				function( event ){

					// Use this internal, UI-click as a reason to
					// trigger a custom event on this component.
					jQuery( self ).trigger({
						type: "submit",
						text: jQuery.trim( self.ui.text() )
					});

				}
			);
		}


		// -------------------------------------------------- //
		// -------------------------------------------------- //


		// When the DOM is ready initialize the scripts.
		jQuery(function( $ ){

			// Create an instance of the para controller.
			var paraController = new ParaController( $( "p" ) );

			// Bind to the custom click event on the component.
			$( paraController ).bind(
				"submit",
				function( event ){

					// Alert the text submitted with this event.
					alert( event.text );

				}
			);

		});

	</script>
</head>
<body>

	<h1>
		Binding The Submit Event On Objects In jQuery
	</h1>

	<p>
		This is a paragraph.
	</p>

</body>
</html>

As you can see, when the user double-clicks on the paragraph, the component traps the click event and announces a "submit" event, adding the text of the paragraph as part of this "custom event." This works fine in FireFox, but in IE, it throws the error:

Line: 2200
this.nodeName is null or not an object.

Looking at line 2200, it appears that jQuery is trying to implement "submit" propagation for browsers that don't inherently support it (which I guess IE does not). To get around this, all you have to do is rename the event to not use the "submit" event type. When you do that, jQuery no longer tries to propagate the event - I believe, by default, jQuery doesn't propagate any custom event types.

I am pretty sure this is a bug; jQuery is probably supposed to be checking the type of the object in the binding before it attempts to use it as a DOM node. This was most likely just an oversight in the new "live" functionality. On a personal note, live-binding a form submission just feels somewhat awkward to me. This is entirely emotional, I understand that, but a form submission doesn't feel like it's in the same league as an event like click. I can understand live-binding click; but submit? It just doesn't feel right.

Want to use code from this post? Check out the license.

Reader Comments

10 Comments

Interesting find - I'm inclined to call that a bug as well. Did you submit a support ticket yet? Regarding the reasoning behind delegated submit events, I think I would defend it for two main reasons:
1) It maintains consistency with the rest of the events API.
2) There are some scenarios in which it is actually very useful. Ajaxified comment threads are a good example - it's nice to be able to simply spin up comment forms anywhere, and not worry about rebinding each of them.

15,841 Comments

@Jeremy,

I have never submitted a jQuery bug ticket before, I will definitely look into it if you think it's a bug as well.

As for submit-propagation, I know what you are saying; that's why I freely admit that my adverse reaction is entirely emotional :) I'll get past it.

7 Comments

So I'm relatively, but not 100%, sure that wrapping jQuery around an arbitrary object isn't actually supported. If you look at the code that inits a jQuery based on (selector,context), you won't see any logic there for handling generic objects. So while it does sorta-kinda work at present, I'm not entirely sure you'll end up seeing a change to the event propagation model to make an unsupported feature work right

7 Comments

Also, if you look at the docs, it says the following types of arguments are allowed to pass to jQuery():

selector - a selector string
element - a DOM node
elementArray - an array of DOM nodes
jQuery object - an existing jQuery object (pointless, but supported)
[no arguments] - returns an empty jQuery object
html - an HTML string
callback - a function. This is a shortcut to $(document).ready();

15,841 Comments

@Adam,

Wow - that just shot some adrenaline up my spine :)

Ok, after a little bit of digging, according to this blog post, although no specific recording has been made, apparently John Resig said that this feature would be embraced and supported:

http://www.mrspeaker.net/2009/11/14/selecting-javascript-objects-with-jquery/

In the comments to that blog, they even make reference to a bug that this stopped being supported, but then I guess was eventually solved (status of linked ticked was changed to "solved.").

It also appears that John Resig filed a bug and a fix for the unbind() to plain javascript objects:

http://dev.jquery.com/ticket/6184

So, while this might be stated explicitly in the documentation, it looks like people, including John, keep taking steps to ensure that it *is* supported in the core.

Perhaps it's time that this DID get put in the documentation?

15,841 Comments

@Jeremy,

That definitely works; but, part of my issue with that approach is that it forces the calling code to make assumptions about how the component, ParaController, will be implementing events as well as how the component will be implementing the UI. This creates coupling between the calling code the internals of the ParaController component.

By keeping the API at the "component" level, it provides for good "implementation hiding".

That said, I am now very curious to see if this object-binding is even officially supported by the jQuery team? If not, then your approach is going to be the only thing inherently available (unless custom event frameworks are added to the objects).

15,841 Comments

@Jeremy,

Ha ha - just saw your second comment :) Hey, every post is really about *good conversation*... and that's what we've got going on here!

15,841 Comments

@Jeremy,

Very interesting! If I had to guess, I'd say when running the extend() method, you are adding all the DOM-native event methods and node properties to the Javascript object. Very funky :) So, I guess, when the code looks at the ParaController instances, it "looks" like a P tag.

10 Comments

@Ben,

Right - the main thing it buys you in this case is that anything jQuery needs for the binding is now available. You basically get to treat it just like the p element itself. You of course have to be careful about overriding stuff, and certain things that are set in the paragraph's constructor might not work. It's not an efficient solution either. Just... interesting.

15,841 Comments

@Patrick,

Thanks my man.

@Kevin,

There's still some disagreement as to whether this feature is actually supported. I've tried contacting some jQuery team members of their input, but have not heard back just yet.

34 Comments

Yeah support may be questionable, but I look at from a pragmatic standpoint. If the environment you are developing for is closed and standards are not 100% mandated why not.

After all if you are in an Oracle shop do you write SQL that works on all platforms or do you optimize for Oracle (this was the case when I was a contractor for US Gov't agency).

The key here is that it is decoupled, so at least you can later go back and replace with a more standards friendly version.

15,841 Comments

@Kevin,

You make a really good point! Of course, when it comes to any framework, the hope is that you have something that can constantly be upgraded as new versions come out. Having to constantly re-edit the event framework, and then re-minify the JS file would just be a pain... and probably open us up to error.

Ideally, I just want the jQuery people to come out and support this publicly.

1 Comments

This is very simple, and is working without problems in my form.

$("#apDiv12").click(function(){
sb = $("#Submit").click();
$(this).bind(sb.click);

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel