@JoJo:

I start this off responding to Eric, but there's some info (useful, I
hope) for you below as well.

@Eric:

> T.J.'s blog has many very well written articles that will explain you
> why...

You're very kind!! :-)

> Also note that I am 80% sure (please somebody confirm) that since your
> parameter is a local variable, javascript will implicitly create a
> closure for you.

Not *implicitly*, no, but your rewrite has an explicit closure and
should absolutely work.

You probably know this, but JoJo's mechanism (or, as you point out,
Function#curry) is necessary in situations where you're going to
change `localVariable` later, for instance loops:

var index, localVariable;
for (index = 0; index < 10; ++index) {
    localVariable = "Hi, I'm index " + index;
    dynamicAnchor = new Element(
        'a', {
            href: 'javascript:void(0)'
        }
    ).observe(
        'click',
        function(event) {                   // <=== Problem
            window.status = localVariable;
            event.stop();
        }
    );
}

The above would create a bunch of anchors *all* of which would show
the message "Hi, I'm index 9", because that's the value of
`localVariable` at the end of the loop. So instead, you need to do
something like what JoJo did, though if you do *exactly* what JoJo did
in a loop, it has to create the factory function on every loop, which
is unnecessary as it's invariant:

var index, localVariable;
for (index = 0; index < 10; ++index) {
    localVariable = "I'm index " + index;
    dynamicAnchor = new Element(
        'a', {
            href: 'javascript:void(0)'
        };
    ).observe(
        'click',
        (function(parameter) { // <== This factory function gets
duplicated
            return function(event) {
                window.status = parameter;
                Event.stop(event);
            }
        })(localVariable);
    );
}

Since nothing keeps a reference to the factory functions, it doesn't
matter much.

@JoJo:

Like Eric, I'd probably use Function#curry. FWIW, this is how I'd
write it:

// Somewhere useful where I can reuse it, because this looks like
// something we'll need to do somewhere else, too
function showStatMsgAndStopHandler(message, event) {
    window.status = message;
    event.stop();
}

// Use it
dynamicAnchor = new Element(
    'a', {
        href: 'javascript:void(0)'
    };
).observe(
    'click',
    showStatMsgAndStopHandler.curry(localVariable)
);

A couple of reasons I'd do it that way:

1. Reuse
2. Well-controlled closures
3. I'm a fan of named functions rather than anonymous ones[1] ;-)
4. Readability (maybe)

With the rewrite, _nothing_ closes over the local variables in the
context in which this dynamic anchor is being created. Assuming you
define `showStatMsgAndStopHandler` in a place you're defining other
generally-useful stuff, the only closures in the rewrite are generated
in the well-controlled scope of Function#curry. So we're not keeping
stuff in memory we don't need.

[1] http://blog.niftysnippets.org/2010/03/anonymouses-anonymous.html

HTH,
--
T.J. Crowder
Independent Software Engineer
tj / crowder software / com
www / crowder software / com

On Oct 25, 4:10 pm, Eric <[email protected]> wrote:
> Hi JoJo,
>
> It seems you're doing a closure "by hand". You may want to look at
> Function.bind() or Function.curry() in prototype documentation, since
> they do it for you.
> Your solution may become :
> dynamicAnchor = new Element(
>     'a', {
>         href: 'javascript:void(0)'
>     }
> ).observe(
>     'click',
>     (function(parameter,event) {
>         window.status = parameter;
>         event.stop();
>     }).curry(localVariable)
> );
>
> Also note that I am 80% sure (please somebody confirm) that since your
> parameter is a local variable, javascript will implicitly create a
> closure for you.
>
> In other words, this should work:
> var localVariable= 'Hi!';
> dynamicAnchor = new Element(
>     'a', {
>         href: 'javascript:void(0)'
>     }
> ).observe(
>     'click',
>     function(event) {
>         window.status = localVariable;
>         event.stop();
>     }
> );
>
> T.J.'s blog has many very well written articles that will explain you
> why (http://blog.niftysnippets.org/search/label/closures).
>
> Eric
>
> On Oct 22, 8:47 pm, JoJo <[email protected]> wrote:
>
>
>
>
>
>
>
> > Thanks T.J.
>
> > The solution is:
>
> > dynamicAnchor = new Element(
> >     'a', {
> >         href: 'javascript:void(0)'
> >     }
> > ).observe(
> >     'click',
> >     function(parameter) {
> >         return function(event) {
> >             window.status = parameter;
> >             Event.stop(event);
> >         }
> >     }(localVariable)
> > );
>
> > On Oct 22, 4:39 am, "T.J. Crowder" <[email protected]> wrote:
>
> > > Hi,
>
> > > See the documentation for `Event.observe`[1] (which is what you're
> > > calling indirectly from the `Element#observe` function), specifically
> > > the "Preventing the Default Event Action and Bubbling" part, and the
> > > `Event` object[2]: You don't return false to cancel the `click` event,
> > > you use the `Event#preventDefault` function (which is a standard DOM
> > > function[3] that Prototype ensures is present even on implementations
> > > that lack it) or, more likely, `Event#stop`[4] which both prevents the
> > > default action and stops the event bubbling.
>
> > > [1]http://api.prototypejs.org/dom/event/observe/
> > > [2]http://api.prototypejs.org/dom/event/
> > > [3]http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event-prev...
> > > [4]http://api.prototypejs.org/dom/event/stop/
>
> > > HTH,
> > > --
> > > T.J. Crowder
> > > Independent Software Engineer
> > > tj / crowder software / com
> > > www / crowder software / com
>
> > > On Oct 22, 2:41 am, JoJo <[email protected]> wrote:
>
> > > > I use anchors to call javascript functions. Usually, I do this:
>
> > > > <a href="javascript:void(0)" onclick="someFunc(); return false;">
> > > >    call the function
> > > > </a>
>
> > > > This works fine in all browsers. Window.onbeforeunload is never
> > > > triggered because the ONCLICK returns false, and thus the HREF if not
> > > > executed. When HREF is not executed, the browser does not believe that
> > > > the window in unloading. Now, I'm trying to create a dynamic anchor to
> > > > accomplish the same thing. It looks nearly identical to the HTML
> > > > anchor, but now it's triggering window.onbeforeunload in IE8. How do I
> > > > not trigger it?
>
> > > > dynamicAnchor = new Element(
> > > >     'a', {
> > > >         href: 'javascript:void(0)',
> > > >     }
> > > > ).observe(
> > > >     'click',
> > > >     function(parameter) {
> > > >         return function() {
> > > >             window.status = parameter;
> > > >             return false;
> > > >         }
> > > >     }(localVariable)
> > > > );

-- 
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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/prototype-scriptaculous?hl=en.

Reply via email to