T.J. & Ryan,

First of all, thanks for all the help!  I have a very good
understanding of bind, and it is working very well.
Unfortunately, I have an issue, and am hoping for some help in
troubleshooting.  The following occurs:

In my keyup event, I have correctly followed T.J.'s suggested
approach.  When the tag is type input "text" I call

this.__find().bind(this)

The first statement in the function __find(), I write a message to a
custom debug window, the method call is:

outwin('__find()');
.. a proof statement, I have actually reached this method.

So, in my debug window I do get "__find()", so the call is
successful.  However, my code breaks with an error on the call above.
The error is:

this.__find() is either null or not an object.

It is possible, that the error occurs deeper than this.  The __find()
calls __find() with a setTimeout of 1 second (waiting 1 second for
user pause).  It is confusing, everything seems to be working.  The
error occurs in both IE and FF.  Let me try to outline the exact
steps:

1)  KeyUp event occurs ==> "keyup"
2)  Invoke, this.__find().bind(this);
3)  this.__find() ==> "__find(): flgactive:true flgUserActive: true
flgAjaxActive: false"
~ i have a pause in my code on Line 132, and at this point no error
has occurred ~

(snippet of code from the __find() method)
    Line 131:        var func = function() { this.__find(input,
false) } .bind(this);
    Line 132:        this.timer = setTimeout(func, 1000);

4) this._find() ==> "__find(): flgactive:false flgUserActive: false
flgAjaxActive: false"
~ I only achieve this when not in debug mode, otherwise this doesn't
occur, when this does occur, the ajax code fires as expected, and
ultimately the code works as expected, except for the error produced ~

~ stepping beyond line 132 my code (in "break for all errors mode")
breaks on this.Find().bind(this), the line in the KeyUp event which
calls this.__find() originally. ~

Did I bind correct?  For reference, here is __find() method in whole:

    __find: function(input, flgactive) {
        outwin('__find(): flgactive:' + flgactive.toString() + '
flgUserActive: ' + this.flgUserActive.toString() + ' flgAjaxActive: '
+ this.flgAjaxActive.toString());

        if (this.timer != null)
            clearTimeout(this.timer);

        if (!flgactive && !this.flgUserActive && !this.flgAjaxActive)
{
            // perform the ajax lookup
            this.flgAjaxActive == true;

            __ajaxFind(input);
        }
        else {
            // call __find itself
            this.flgUserActive = false;

            var func = function() { this.__find(input, false) } .bind
(this);
            this.timer = setTimeout(func, 1000);

            return;
        }

    }


Thanks for the help.  I hope this is all clear enough.
Karl..

On Apr 10, 8:33 am, Ryan Gahl <ryan.g...@gmail.com> wrote:
> > That's not bind(), that's Event.observe().  bind() is general-purpose,
> > knows nothing about events.
>
> D'oh! That's an obvious blunder in my reply. Thanks :)
>
> Ryan Gahl
> CEO
> Nth Penguin, LLChttp://www.nthpenguin.com
> --
> Inquire: 1-920-574-2218
> Blog:http://www.someElement.com
> LinkedIn Profile:http://www.linkedin.com/in/ryangahl
>
> On Fri, Apr 10, 2009 at 10:30 AM, T.J. Crowder 
> <t...@crowdersoftware.com>wrote:
>
>
>
> > Hey Ryan,
>
> > Thanks.  It was too long, though, really.
>
> > > FWIW, I know bindAsEventListener isn't actually legacy...
>
> > Yeah, I was thinking about that, and since one of its two main reasons
> > for being is DOM0-style handlers, "legacy" isn't necessarily the wrong
> > word... :-)
>
> > BTW, meant to mention:
>
> > > Note, I believe .bind() automagically passes the event object along to
> > the
> > > bound function these days...
>
> > That's not bind(), that's Event.observe().  bind() is general-purpose,
> > knows nothing about events.  If you're using a DOM0 handler, bind()
> > won't help you out with IE's window.event thing.  bindAsEventHandler()
> > will (it ensures that the first argument is the event object [even on
> > IE] -- an unextended event object, but an event object).  But why
> > would you use a DOM0 handler? ;-)
>
> > -- T.J. :-)
>
> > On Apr 10, 3:00 pm, Ryan Gahl <ryan.g...@gmail.com> wrote:
> > > Thanks for jumping in TJ, great response!
>
> > > FWIW, I know bindAsEventListener isn't actually legacy - I guess I was
> > just
> > > being a bit lazy in my response and was sort of just implying that it
> > > probably wasn't needed (I have never had to use it).
>
> > > You certainly have a knack for the more detailed replies :)
>
> > > Ryan Gahl
> > > CEO
> > > Nth Penguin, LLChttp://www.nthpenguin.com
> > > --
> > > Inquire: 1-920-574-2218
> > > Blog:http://www.someElement.com
> > > LinkedIn Profile:http://www.linkedin.com/in/ryangahl
>
> > > On Fri, Apr 10, 2009 at 5:39 AM, T.J. Crowder <t...@crowdersoftware.com
> > >wrote:
>
> > > > Hi,
>
> > > > >         this.MSOFindForm.getInputs('text').each(function(input) {
> > > > >             Event.observe(input, 'keyup',
> > this.Find.bindAsEventListener
> > > > > (this));
> > > > >         });
> > > > > The above is part of the initialize event for the class MSOFindForm.
>
> > > > A few things that may help:
>
> > > > bindAsEventListener()
> > > > ---------------------
> > > > It's _extremely_ rare to need to use bindAsEventListener(), and you
> > > > don't need to in this case.  You just need bind(), because you're not
> > > > burning in (currying) any other arguments in your event handler that
> > > > need to follow the event object.  It's not a legacy form of bind() as
> > > > Ryan suggested earlier, it's a highly specific solution to a highly
> > > > specific problem you don't have in this code. :-)
>
> > > > So to start with, use bind() instead of bindAsEventListener() in the
> > > > code above.  But that won't solve the "Find" problem...
>
> > > > each()
> > > > ------
> > > > Remember that Enumerable#each() calls the iterator function you
> > > > provide.  The act of calling a function sets the "context" of that
> > > > function, including what "this" means.  Unless you do something
> > > > specific to set the context, within a function "this" will default to
> > > > the global object, which is "window" in browser implementations.  So
> > > > no matter what "this" means outside an each() loop, unless you do
> > > > something on purpose, this === window within the loop.
>
> > > > So in this code:
>
> > > >    this.MSOFindForm.getInputs('text').each(function(input) {
> > > >         Event.observe(input, 'keyup', this.Find.bind(this));
> > > >    });
>
> > > > it doesn't matter what "this" means outside the iterator function,
> > > > *inside* the iterator, this === window.
>
> > > > Now, you can _tell_ each() what context it should use when calling the
> > > > iterator function, which would fix that problem and probably make that
> > > > code work; see the docs[1].  But wait, there's more we can do...
>
> > > > [1]http://prototypejs.org/api/enumerable/each
>
> > > > Bind once, use many
> > > > -------------------
> > > > That code is doing something else you probably want to fix:  It's
> > > > creating a whole lot more functions than it has to.  On every loop,
> > > > it's doing this:
>
> > > >    Event.observe(input, 'keyup', this.Find.bind(this));
>
> > > > Remember that bind() [like bindAsEventListener()] creates a *new
> > > > function* every time it's called, and returns that function.  The
> > > > purpose of the new function is to set the context ('this') correctly
> > > > when calling the original function.  You don't need a separate
> > > > function for every text element, they all do exactly the same thing:
> > > > They set "this" to the MSOFindForm and then call Find.  Instead,
> > > > create your bound function once, then reuse it, like so:
>
> > > >    var handler;
> > > >    handler = this.Find.bind(this);
> > > >     this.MSOFindForm.getInputs('text').each(function(input) {
> > > >         Event.observe(input, 'keyup', handler);
> > > >    });
>
> > > > That creates the function just once, and then reuses it for each
> > > > input.  You could also do it with Enumerble#invoke[2]:
>
> > > >    this.MSOFindForm.getInputs('text').invoke(
> > > >        'observe',
> > > >        'keyup',
> > > >        this.Find.bind(this)
> > > >    );
>
> > > > Event delegation
> > > > ----------------
> > > > 'keyup' is a bubbling event, so you could use a single handler on the
> > > > form element instead of individual handlers on the text elements; the
> > > > form's handler can use event.findElement() to find the actual element
> > > > the keyup occurred in.  This is frequently called event delegation.
> > > > [3]  Very roughly:
>
> > > >    // During initialization
> > > >    $('formid').observe('keyup', this.handleKeyUp.bind(this));
>
> > > >    // In your class
> > > >    handleKeyUp:  function(event) {
> > > >        var element;
>
> > > >        // Get the element the event actually occurred on
> > > >        element = event.findElement();
>
> > > >        // Is it a text field?
> > > >        if (element.tagName.toLowerCase() == 'input' &&
> > > >            element.type == 'text') {
> > > >            // keyup logic goes here
> > > >        }
> > > >    }
>
> > > > [2]http://prototypejs.org/api/enumerable/invoke
> > > > [3]http://proto-scripty.wikidot.com/faq#delegation
>
> > > > FWIW & HTH,
> > > > --
> > > > T.J. Crowder
> > > > tj / crowder software / com
> > > > Independent Software Engineer, consulting services available
>
> > > > On Apr 10, 3:52 am, kstubs <kst...@gmail.com> wrote:
> > > > > So I'm trying to setup the keyup event for my form inputs like this:
>
> > > > >         this.MSOFindForm.getInputs('text').each(function(input) {
> > > > >             Event.observe(input, 'keyup',
> > this.Find.bindAsEventListener
> > > > > (this));
> > > > >         });
>
> > > > > The above is part of the initialize event for the class MSOFindForm.
> > > > > The MSOFindForm has a Find method.  I am getting an error though,
> > > > > which says that this.Find is not defined.  Uggg, I'm confused.
>
> > > > > Karl..
>
> > > > > On Apr 9, 4:17 pm, Ryan Gahl <ryan.g...@gmail.com> wrote:
>
> > > > > > OK
>
> > > > > > Someone might want to jump in here, as I'm not 100% of the behavior
> > of
> > > > the
> > > > > > passed in event obj.
>
> > > > > > Basically I think you can just do the following:
>
> > > > > > var func = function() { this.Find(input, objEvent, false);
> > > > }.bind(this);
>
> > > > > > > //get rid of the func = func.bind(this) line and just bind inline
>
> > > > > >  since the variables input and objEvent are closed over that should
> > be
> > > > all
> > > > > > you need to do. The caveat to that is if the objEvent reference
> > changes
> > > > with
> > > > > > other events that happen after you set up the timer, and that's
> > where
> > > > > > someone like kangax can probably jump in and say yea or nay
> > immediately
> > > > (of
> > > > > > course you can just try it).
>
> > > > > > If that doesn't work, then you might want to create the timer in
> > such a
> > > > way
> > > > > > that it passes just the keycode part of the event object (which is
> > all
> > > > you
> > > > > > seem to need). I can see that looking kind of like this:
>
> > > > > > Find: function(input, objEvent, useractive) {
>
> > > > > > >    var keycode = objEvent.keyCode;
> > > > > > >    this.__doFind(input, keycode, useractive);
> > > > > > > },
> > > > > > > __doFind: function(input, keycode, useractive) {
> > > > > > >     this.flgUserActive = useractive;
>
> > > > > > >    // keycode ignore list
> > > > > > >    if (this.aKeyCodeIgnoreList.include(keycode))
> > > > > > >        return false;
>
> > > > > > >    // ajax spinning (no action)
> > > > > > >    if (this.flgAjaxActive)
> > > > > > >        return;
>
> > > > > > >    // user typing (no immediate action, set timer)
> > > > > > >    if (this.flgUserActive) {
> > > > > > >        this.flgUserActive = false;
>
> > > > > > >        var form = this.MSOFindLayer.select('form')[0];
>
> > > > > > >        //test 2 leters in 1st word for up to two words (trailing
> > > > space is
> > > > > > > bad)
> > > > > > >        if
> > > > (!($(input).value.match(/^[a-zA-Z]{2,40}(.[a-zA-Z]{1,40})?$/im)))
> > > > > > >            return;
>
> > > > > > >        if (this.timer != null)
> > > > > > >            clearTimeout(this.timer);
>
> > > > > > >        var func = function() { this.__doFind(input, keycode,
> > false);
> > > > > > > }.bind(this);
> > > > > > >        this.timer = setTimeout(func, 300);
>
> > > > > > >        return;
> > > > > > >    }
>
> > > > > > >    // if we made it this far, call the find
> > > > > > >    __find(input);
> > > > > > > }
>
> > > > > > Ultimately, though, you should be attaching your listeners via
> > > > javacript,
> > > > > > which in this case will
>
> ...
>
> read more »
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Prototype & script.aculo.us" group.
To post to this group, send email to prototype-scriptaculous@googlegroups.com
To unsubscribe from this group, send email to 
prototype-scriptaculous+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/prototype-scriptaculous?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to