views:

5716

answers:

7

Update: As of jQuery 1.4, $.live() now supports focusin and focusout events.


jQuery currently1 doesn't support "blur" or "focus" as arguments for the $.live() method. What type of work-around could I implement to achieve the following:

$("textarea")
  .live("focus", function() { foo = "bar"; })
  .live("blur",  function() { foo = "fizz"; });

1. 07/29/2009, version 1.3.2

+2  A: 

live() is jQuery's shortcut to event delegation. To answer your question, see Delegating the focus and blur events.

It's pretty ingenious: for standards compliant browsers he uses event capturing to trap those events. For IE he uses IE's proprietary focusin (for focus) and focusout (for blur) events, which do bubble, allowing traditional event delegation.

I'll leave the porting of it to jQuery as an exercise.

Crescent Fresh
Did the port :) (see my answer)
J-P
+24  A: 

Working solution:

(function(){

    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);

    jQuery.event.special.focus = {
        setup: function() {
            var _self = this,
                handler = function(e) {
                    e = jQuery.event.fix(e);
                    e.type = 'focus';
                    if (_self === document) {
                        jQuery.event.handle.call(_self, e);
                    }
                };

            jQuery(this).data(uid1, handler);

            if (_self === document) {
                /* Must be live() */
                if (_self.addEventListener) {
                    _self.addEventListener('focus', handler, true);
                } else {
                    _self.attachEvent('onfocusin', handler);
                }
            } else {
                return false;
            }

        },
        teardown: function() {
            var handler = jQuery(this).data(uid1);
            if (this === document) {
                if (this.removeEventListener) {
                    this.removeEventListener('focus', handler, true);
                } else {
                    this.detachEvent('onfocusin', handler);
                }
            }
        }
    };

    jQuery.event.special.blur = {
        setup: function() {
            var _self = this,
                handler = function(e) {
                    e = jQuery.event.fix(e);
                    e.type = 'blur';
                    if (_self === document) {
                        jQuery.event.handle.call(_self, e);
                    }
                };

            jQuery(this).data(uid2, handler);

            if (_self === document) {
                /* Must be live() */
                if (_self.addEventListener) {
                    _self.addEventListener('blur', handler, true);
                } else {
                    _self.attachEvent('onfocusout', handler);
                }
            } else {
                return false;
            }

        },
        teardown: function() {
            var handler = jQuery(this).data(uid2);
            if (this === document) {
                if (this.removeEventListener) {
                    this.removeEventListener('blur', handler, true);
                } else {
                    this.detachEvent('onfocusout', handler);
                }
            }
        }
    };

})();

Tested in IE/FF/Chrome. Should work exactly as you intended.

UPDATE: Teardowns now work.

J-P
Holy shit. Nice job.
Crescent Fresh
Now go to the jQuery bug tracker and provide the patch. Good job.
Ionuț G. Stan
Will `die()` route to `teardown` here?
Crescent Fresh
Yep, I think so... jQuery takes care of most of it in the background (including the "handling"). Just updated the teardowns so the appropriate events are detached.
J-P
Many Thanks. Solved a problem I was having perfectly.
Sniffer
how do you use this function?
weng
NOTE: this is no longer necessary. jQuery 1.4 supports this natively, via the `focusin` and `focusout` events.
J-P
Just a suggestion: in the above code sample, `+new Date()` can be shortened to `+new Date`. The brackets aren’t required (unless you need to pass arguments, of course).
Mathias Bynens
A: 

How does the above example work?

The original query was:

$("textarea")
.live("focus", function() { foo = "bar"; })
.live("blur", function() { foo = "fizz"; });

I can't see how the working example given relates to that. For instance, whats with the date variables, and what is the teardown function?

I appreciate that this is not an answer, but I don't know how to post questions that follow up existing answers.

The posted answer allows the OP to use the code he wanted (the code you posted). The long chunk of code in the answer is basically a mod for jQuery.
J-P
THanks for the quick response! So what would I do with your working solution? Are you saying that I just paste it into a .ready() function? Sorry for such a basic question but I am at the start of the learning curve.
It doesn't have to go in the ready() handler. Simply put it within `<script>...</script>` ... Just make sure that the script is placed after jQuery. jQuery must be loaded before this script runs. ... Also make sure that this script appears before where you intend to use it with live(). Look here: http://gist.github.com/207904
J-P
Woo hooo! Works a charm. You star. Am I correct in assuming that the date is just used to create a unique ID? Who knows, in a few years time I might even understand how your code actually works.
A: 

one more addition: this solution does not support more than one parameter.

i tried:

$(el).live("focus blur", function(e) { if (e.type == "focus") {

etc.

and it only fired the blur event.

nevertheless this solution has been helpful.

Maarten
A: 

VERY COOL!!! Thank you so much for taking the time to post this. It worked really well for me.

MickDizzle
+1  A: 

This functionality is now included in jQuery core (as of 1.4.1).

Ville
I noted this already in my question.
Jonathan Sampson
A: 

they have been added on jquery 1.4.1 ... now .live() function supports fucus and blur events =) Greetings

Matias