> > this.__find().bind(this) > Ask yourself "what does this.__find() return"... and then ask "what does .bind() work on, and what does it return"
.bind() is a method on the Function type (prototype.js extends the Function.prototype in javascript so that it has this .bind() method on it). Therefore, it is only valid to call .bind ON A FUNCTION. So, does this.__find() return a function? Also, .bind() returns a _new_ function, which is a wrapper around the original function with whatever object you pass into being set as the internal "this" keyword. Having said all that, chances are you don't even need to .bind(this) on this.__find(). Remember, only call .bind on a function REFERENCE, not the result of a function's execution. The caveat to that, of course, is if you have some (very rare) scenario where you have a factory method that returns function references and you need those new functions to be scope corrected via .bind(). Ryan Gahl CEO Nth Penguin, LLC http://www.nthpenguin.com -- Inquire: 1-920-574-2218 Blog: http://www.someElement.com LinkedIn Profile: http://www.linkedin.com/in/ryangahl On Sat, Apr 11, 2009 at 4:46 PM, kstubs <kst...@gmail.com> wrote: > > 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 -~----------~----~----~----~------~----~------~--~---