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 probably make life a little easier.
>
> > 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 Thu, Apr 9, 2009 at 4:55 PM, kstubs <kst...@gmail.com> wrote:
> > > var func = function(input, objEvent) { this.Find(input,
> > > objEvent, false); };
>
>
--~--~---------~--~----~------------~-------~--~----~
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