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.
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:
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.
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.
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.
Bug ticked filed :)
Awesome - I hunted down the ticket url in case anyone else is interested: http://dev.jquery.com/ticket/6398
It's exciting. I've never "contributed" anything to the project before.
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
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();
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:
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.").
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?
Ya - for some reason I thought you were binding/triggering against "self.target", not "self". Not sure whether or not this snippet really makes any sense, but you do something similar to this example by keeping all the event logic DOM-centric: http://jsbin.com/uneke/2/edit
... although by keeping it DOM-centric, it really just avoids the entire point of this post :)
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).
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!
If you tell anyone I recommended this, I'll hunt you down - but this is somewhat interesting (in that it makes IE work): http://jsbin.com/ayufe3/2/edit
In theory, this should allow for most any jQuery operation to work on the controller.
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.
Nothing wrong with playing around outside the box.
Thank you so much for awesome write-up. Very interesting and insightful.
Excellent post and the comments very informative. Really need to go back to jQuery docs and do some reading.
Thanks my man.
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.
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.
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.
This is very simple, and is working without problems in my form.
sb = $("#Submit").click();