Dynamically assigning functions with parameters to events

B

Biguana

Hello there,

I'm having a real problem with assigning a function, and I've googled
quite a bit but am not really sure what to look for. :eek:(

I have a function (setuplinks) which I am attempting to use to assign
another function (eventfunc) to the onmouseover event handler of a
group of a-tags on my page (recognised by their class). setuplinks is
called when the page is loaded. I have used similar javascript before
and it's worked fine. The difference is that I am trying to add a
parameter which I work out at the runtime of the setup function.

function setuplinks()
{
var atags = document.getElementsByTagName('a');

for (var i=0; i < atags.length; i++)
{
if(atags.className=='groups-period')
{
var x;
x = atags.id.replace('gp','tip');
atags.onmouseover=function(event){eventfunc(event,x);};
}
}
}

What I want the mouseover to do is - eventfunc(event,'tip123')
- or similar (x='tip123' when setuplinks runs), but the function
just seems to assign the reference to x, and all the links all call
eventfunc with the last value of x that was used (on the last loop).
Surely it can't permanently use x as a parameter, because when
eventfunc runs x is out of scope?! But it also doesn't use the value
of x (or only the last value).

Can anyone explain or help? Thank you in advance.

Tim
 
T

Thomas 'PointedEars' Lahn

Biguana said:
I have a function (setuplinks) which I am attempting to use to assign
another function (eventfunc) to the onmouseover event handler of a
group of a-tags on my page (recognised by their class). setuplinks
is called when the page is loaded.

You shouldn't do that. The `mouseover' event bubbles in the W3C DOM and in
the MSHTML DOM, so use event bubbling instead.
I have used similar javascript before
and it's worked fine. The difference is that I am trying to add a
parameter which I work out at the runtime of the setup function.

function setuplinks()
{
var atags = document.getElementsByTagName('a');

for (var i=0; i < atags.length; i++)
{
if(atags.className=='groups-period')
{
var x;
x = atags.id.replace('gp','tip');


I really don't see the point in this.
atags.onmouseover=function(event){eventfunc(event,x);};
}
}
}


You should use

<head>
...
<meta http-equiv="Content-Script-Type" content="text/javascript">
<script type="text/javascript">
function handleLinkMouseover(e)
{
var t = e.target || e.srcElement;
if (t && /a/i.test(t.tagName)
&& /\bgroups-period\b/i.test(t.className))
{
// body of eventfunc() goes here
}
}
</script>
</head>

<body onmouseover="handleLinkMouseover(event)">
...
</body>

instead.
What I want the mouseover to do is - eventfunc(event,'tip123')
- or similar (x='tip123' when setuplinks runs), but the function
just seems to assign the reference to x, and all the links all call
eventfunc with the last value of x that was used (on the last loop).

This is called a closure, and it works as designed.
Surely it can't permanently use x as a parameter, because when
eventfunc runs x is out of scope?!

If it is declared a *local* variable.
But it also doesn't use the value of x (or only the last value).

Using the alternative approach below should make the problem to disappear
already.


PointedEars
 
B

Biguana

PointedEars,

Thank you for taking the time to reply. After posting I had actually
updated my code so setuplinks just passes the event and the srcElement
to a function passingfunc:

atags.onmouseover=function(event){passingfunc(event,this);};

which in turn does the work at mouseover-time:

function passingfunc(e,caller)
{
e = e || window.event;
var x = caller.id.replace('gp','tip');
eventfunc(e,x);
}


This also takes care of ie managing the events differently and seems
to work fine in ie7, firefox and safari (for windows at least).

However it obviously still doesn't use your event bubbling model, but
your example seems to assign the event handler in the tag, which I was
informed was wrong? (sorry, I'm a bit of a newb). I was hoping to
just plug my JS into a page that contains the appropriate classes and
let it do all the work?
I really don't see the point in this.

Apologies for not explaining. It goes through the <a> tags and if it
finds one with the class 'groups-period' and (for example) id 'gp123'
it needs to call eventfunc(e,'tip123') (eventfunc shows a tooltip -
'tip123' is the id of the div for tooltip for the link with id gp123).
If it is declared a *local* variable.

Surely that means declared in the function, as it is? In fact it's
declared in the loop (not that it makes any difference where it's
declared, the result is the same).
Using the alternative approach below should
make the problem to disappear already.

But it also means making each <a> tag as follows:

<a href='urlstuff' class='groups-period' id='gp123'
onmouseover='eventfunc(event)' >

and I've been informed (perhaps misinformed) that javascript should be
kept out of links.

Obviously the matter is less urgent as I have a version that works (at
least to my satisfaction for now), but I would be interested in your
views.

Thanks,

Tim
 
H

Henry

Thomas 'PointedEars' Lahn wrote:

But it also means making each <a> tag as follows:

<a href='urlstuff' class='groups-period' id='gp123'
onmouseover='eventfunc(event)' >

and I've been informed (perhaps misinformed) that javascript
should be kept out of links.

Obviously the matter is less urgent as I have a version that
works (at least to my satisfaction for now), but I would be
interested in your views.

It is rarely a good idea to do what you are told to do in javascript/
web-development because you have been told but instead to understand
why you are being told and what the consequences/costs/benefits of
doing as you are told are. The (or maybe a) proposed benefit of
avoiding putting javascript intrinsic event attributes in the HTML is
a separation, presumably of content from mechanism. But here you have
an obvious example of falling to achieve anything of the sort.

Each of your anchors of interest have a class attribute, and if that
attribute is being used to apply CSS styles that is seemingly only a
coincidence as there primarily purpose seems to be to facilitate
mechanism. Then you have ID attributes that look like the only purpose
they serve is to provide cross-referencing data for the tool tips.
Thus some aspects of the mechanism and its data are still in the HTML
(so no real separation) and you are having to accept the overheads of
a searching for the significant fields and attaching handlers.

So instead of:-

<a href='urlstuff' class='groups-period' id='gp123'>

You could have had:-

<a href='urlstuff' onmouseover='eventfunc(event, this, '123');'>

- and have all the javascript related stuff wrapped up in one
attribute that you either use on an A element or not (rather than
spread across two attributes), and leave the ID and CLASS attributes
free for uses more related to their intended purpose. There is more
separation of content from mechanism in this second alternative than
your first because it draws a much tighter line around what is
javascript related and what is not.
 
T

Thomas 'PointedEars' Lahn

Biguana said:
Thank you for taking the time to reply.

You're welcome.
After posting I had actually updated my code so setuplinks just passes
the event and the srcElement to a function passingfunc:

Why both? Event::target (DOM Level 2 Events) and Event::srcElement (MSHTML
DOM) exist.
atags.onmouseover=function(event){passingfunc(event,this);};

which in turn does the work at mouseover-time:

function passingfunc(e,caller)
{
e = e || window.event;
var x = caller.id.replace('gp','tip');
eventfunc(e,x);
}

This also takes care of ie managing the events differently and seems
to work fine in ie7, firefox and safari (for windows at least).


It is unnecessarily inefficient: You have to loop through all elements, to
test each element, to create a Function object (therefore allocate memory
for it) for each matching element, and to assign the event listener for the
`mouseover' event for each matching element. Worst Case scenario is that
you have one link in a huge HTML document with many other elements that the
cursor of the pointing device (if there is any) is never moved over, and all
this was for nothing.

It is unreliable: Provided that it even works (using `onmouseover' is a
proprietary approach that is not even partially endorsed by Web standards),
the user may hover over one link before you have been able to set the event
listener for it.
However it obviously still doesn't use your event bubbling model, but
your example seems to assign the event handler in the tag, which I was
informed was wrong? (sorry, I'm a bit of a newb).

You have been misinformed (through Danny Goodman's "JavaScript Bible" by any
chance?). `onmouseover' is an attribute of the `body' element in Valid HTML
4.01 Strict, XHTML 1.0 Strict, and XHTML (Basic) 1.1, and so may appear in
its start tag. [1] It is also the most compatible (incl. IE) and so far the
less maintenance-demanding approach.
I was hoping to just plug my JS into a page that contains the appropriate
classes and let it do all the work?

It does.
Apologies for not explaining. It goes through the <a> tags and if it
finds one with the class 'groups-period' and (for example) id 'gp123'
it needs to call eventfunc(e,'tip123') (eventfunc shows a tooltip -
'tip123' is the id of the div for tooltip for the link with id gp123).

Why not simply use CSS directly instead?
Surely that means declared in the function, as it is?
Yes.

In fact it's declared in the loop (not that it makes any difference
where it's declared, the result is the same).

Yes, because all interoperable ECMAScript implementations so far do not
support block scoping; all variable instantiation takes place before
execution. (JavaScript 1.7 implements block scoping now with the `let'
statement, but it is not an interoperable implementation as it is restricted
to UAs based on Gecko 1.8.1+.)
But it also means making each <a> tag as follows:

<a href='urlstuff' class='groups-period' id='gp123'
onmouseover='eventfunc(event)' >

It doesn't. I have never wrote about setting the `onmouseover' attribute
for every `a' element. In fact, not having to do that is what event
bubbling is all about.
and I've been informed (perhaps misinformed) that javascript should be
kept out of links.

You have been misinformed, or you have misunderstood. It is appropriate to
use event handler attributes to perform scripting with links (and HTML
elements in general), as long as the DTD or an internal subset defines those
attributes for the particular element (it does in this case[1]). However,
the following is not acceptable in most cases:

<a href="javascript:...">...</a>

See also http://jibbering.com/faq/#FAQ4_24 and http://validator.w3.org/checklink

[1]
http://www.w3.org/TR/html4/struct/global.html#h-7.5.1
http://www.w3.org/TR/html4/sgml/dtd.html#events
http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_body
http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_attrs
http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_events
http://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html#dtdelement_body.qname
Obviously the matter is less urgent as I have a version that works (at
least to my satisfaction for now),

You have a lot to learn, young apprentice. That it works in a handful of
tests in a handful of versions of a handful of Web browsers is *never* a
mark of good quality for client-side script code. You have to able to prove
that it can not break.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Henry said:
So instead of:-

<a href='urlstuff' class='groups-period' id='gp123'>

You could have had:-

<a href='urlstuff' onmouseover='eventfunc(event, this, '123');'>

- and have all the javascript related stuff wrapped up in one
attribute that you either use on an A element or not (rather than
spread across two attributes), and leave the ID and CLASS attributes
free for uses more related to their intended purpose. [...]

IBTD: Compared to the current approach, it would be a maintenance nightmare.
Event bubbling is better than both of them for several reasons, including
reduced maintenance efforts.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Thomas said:
It is unreliable: Provided that it even works (using `onmouseover' is a
proprietary approach that is not even partially endorsed by Web standards),
[...]

Please don't misunderstand: I am referring to the proprietary `onmouseover'
_property_ of course, not to the corresponding standardized (X)HTML element
event handler attribute. (See the rest of my posting.)
 
J

jidixuelang

Hello there,

I'm having a real problem with assigning a function, and I've googled
quite a bit but am not really sure what to look for. :eek:(

I have a function (setuplinks) which I am attempting to use to assign
another function (eventfunc) to the onmouseover event handler of a
group of a-tags on my page (recognised by their class). setuplinks is
called when the page is loaded. I have used similar javascript before
and it's worked fine. The difference is that I am trying to add a
parameter which I work out at the runtime of the setup function.

function setuplinks()
{
var atags = document.getElementsByTagName('a');

for (var i=0; i < atags.length; i++)
{
if(atags.className=='groups-period')
{
var x;
x = atags.id.replace('gp','tip');
atags.onmouseover=function(event){eventfunc(event,x);};
}
}

}

What I want the mouseover to do is - eventfunc(event,'tip123')
- or similar (x='tip123' when setuplinks runs), but the function
just seems to assign the reference to x, and all the links all call
eventfunc with the last value of x that was used (on the last loop).
Surely it can't permanently use x as a parameter, because when
eventfunc runs x is out of scope?! But it also doesn't use the value
of x (or only the last value).

Can anyone explain or help? Thank you in advance.

Tim


atags.onmouseover=function(event){eventfunc(event,this.id);};
 
H

Henry

Henry said:
So instead of:-
<a href='urlstuff' class='groups-period' id='gp123'>
You could have had:-
<a href='urlstuff' onmouseover='eventfunc(event, this, '123');'>
- and have all the javascript related stuff wrapped up in one
attribute that you either use on an A element or not (rather than
spread across two attributes), and leave the ID and CLASS
attributes free for uses more related to their intended
purpose. [...]

IBTD: Compared to the current approach, it would
be a maintenance nightmare.

Compared with the current method it should be equivalent or less
maintenance. Consider what the maintenance is; The elements have to be
flagged in a way that will associate them with the mechanism that
applies to them, so that may need to be kept up to date if the mark-up
is going to change, and the elements need to be associated with
another element that contains their tool tip, so that association
needs to be correct, unique and the tool tip element must exist for
each.

None of those things change however this is done. But in my opinion
putting both the indicator that the element is associated with the
mechanism and the data it needs to find the tool tip element into one
attribute, and having that attribute being self-evidently javascript
related (rather than potentially looking presentational) should
improve the clarity of what is going on, which usually makes
maintenance easier.
Event bubbling is better than both of them for several reasons,
including reduced maintenance efforts.

It has the advantage of not requiring the original's action of looping
through the elements in order to set up (and so is available sooner)
and uses fever function objects than using intrinsic event attributes,
but does not change the requirement to mark the elements of interest
as being of interest and providing them with the date needed to make
the association (or maintain the subjects of those associations).
 
T

Thomas 'PointedEars' Lahn

Henry said:
Henry said:
So instead of:-
<a href='urlstuff' class='groups-period' id='gp123'>
You could have had:-
<a href='urlstuff' onmouseover='eventfunc(event, this, '123');'>
- and have all the javascript related stuff wrapped up in one
attribute that you either use on an A element or not (rather than
spread across two attributes), and leave the ID and CLASS
attributes free for uses more related to their intended
purpose. [...]
IBTD: Compared to the current approach, it would
be a maintenance nightmare.

Compared with the current method it should be equivalent or less
maintenance. Consider what the maintenance is; The elements have to be
flagged in a way that will associate them with the mechanism that
applies to them, so that may need to be kept up to date if the mark-up
is going to change, and the elements need to be associated with
another element that contains their tool tip, so that association
needs to be correct, unique and the tool tip element must exist for
each.

None of those things change however this is done. [...]

Wrong. Using event bubbling holds the code in only two places: the event
listener (which may even be outsourced) and the start tag of the element
where the event finally bubbles up to. It also allows for easily changing
the element selection condition later, while your method requires every
element to be changed manually, and the attached script code changed
uniformly (copy and paste, and search and replace, for sure, but nonetheless
much greater an effort).
It has the advantage of not requiring the original's action of looping
through the elements in order to set up (and so is available sooner)
and uses fever function objects than using intrinsic event attributes,
but does not change the requirement to mark the elements of interest
as being of interest and providing them with the date needed to make
the association (or maintain the subjects of those associations).

The need for marking the elements would depend on the element selection
condition. However, event bubbling does also remove the requirement of
maintaining more than two pieces of code, distributed all over the document.


PointedEars
 
H

Henry

Henry said:
Henry wrote:
So instead of:-
<a href='urlstuff' class='groups-period' id='gp123'>
You could have had:-
<a href='urlstuff' onmouseover='eventfunc(event, this, '123');'>
- and have all the javascript related stuff wrapped up in one
attribute that you either use on an A element or not (rather
than spread across two attributes), and leave the ID and CLASS
attributes free for uses more related to their intended
purpose. [...]
IBTD: Compared to the current approach, it would
be a maintenance nightmare.
Compared with the current method it should be equivalent or
less maintenance. Consider what the maintenance is; The elements
have to be flagged in a way that will associate them with the
mechanism that applies to them, so that may need to be kept up
to date if the mark-up is going to change, and the elements need
to be associated with another element that contains their tool
tip, so that association needs to be correct, unique and the
tool tip element must exist for each.
None of those things change however this is done. [...]

Wrong. Using event bubbling

Was event bubbling the "current approach" you were making the
comparison with?
holds the code in only two places: the event listener (which may even
be outsourced) and the start tag of the element
where the event finally bubbles up to.

Fixating on the code is neglecting the fact that the event handler
still needs to know which elements it needs to act upon and which tool
tips to associate with those elements. That information needs to be
somewhere, and it is most likely to be in the mark-up for the elements
themselves (unless the whole system machine generates the mark-up, in
which case it could be in machine generated javascript).
It also allows for easily changing the element selection condition
later, while your method requires every element to be changed
manually,

If the selection criteria are a CLASS attribute on the element then it
makes no difference, you still have to go to the element mark-up to
add/remove elements.
and the attached script code changed uniformly (copy and paste,
and search and replace, for sure, but nonetheless much greater
an effort).

Not significantly different form having to go looking for ID and CLASS
attributes in the mark-up, except searching for the (theoretically
distinct) function name will find all instances of interest and not
risk being distracted by finding non-relevant class attributes,
missing single class names in class name lists, or moving from the
CLASS attribute to the associated ID attribute.
The need for marking the elements would depend on the element
selection condition.

Maybe, but in contexts where things like selecting by element context
or x-path were likely criteria the odds would be good that the mark-up
was machine generated and the maintenance issues would be very
different.
However, event bubbling does also remove the requirement of
maintaining more than two pieces of code, distributed all
over the document.

That is not a significant issue when the intrinsic event attribute
code is only a single function call. Most code modifications would be
in the (single) function definition for the function called, and if
that function gets the event object, the element and the significant
date as its arguments the call to the function would be unlikely to
change and so the mark-up would not need changing. So the act of
setting up an element would be no more than pasting the attribute with
its value into the mark-up and updating its information about the
associated tool tip reference, and removing the mechanism form the
element is just removing that attribute. The distribution of the
attribute through the document acts to mark the elements as included
in the mechanism in itself.
 
D

dhtmlkitchen

Event bubbling is better than both of them for several reasons,
including
reduced maintenance efforts.

Go with bubbling. Much cleaner, as Thomas pointed out. More efficient
as well.

In Biguana's case, extra arguments are completely unnecessary.

The desire to pass multiple parameters to an event sometimes arises
and is always is a bad idea. There is an AOP way to go about this,
using apply, it is possible to invoke the fp with multiple arguments.
YUI made this decision early on and are stuck with it in the API. If
you want to pass multiple arguments; Use an object.

SpecialEvent = function SpecialEvent( domEvent, foo ) {
this.domEvent = domEvent;
this.foo = foo;
};
 
T

Thomas 'PointedEars' Lahn

Your quoting was borken, I repaired it.
Go with bubbling. Much cleaner, as Thomas pointed out. More efficient
as well.

In Biguana's case, extra arguments are completely unnecessary.

`event' would have to be passed because one would need access to the event
target, and that object has a property that refers to it. Unless someone
has a better idea to do that, I am going with it.
The desire to pass multiple parameters to an event sometimes arises
and is always is a bad idea.

You should get your terminology right. You cannot pass anything to an
event. You, the programmer, cannot even pass anything to an event listener
(method), because it has a specific signature that is defined by the UA's
DOM. You can assign an event listener to an event handler. And you can
pass something to a method that is called from an event listener.

In the case of an intrinsic event handler attribute, as in this case,
the event handler (`onmouseover') is specified by the attribute name, and
the body of the event listener is defined by the value of the attribute,
with the (so far) cross-browser peculiarity that there is an `event'
property in the scope chain of the event listener execution context
to refer to the corresponding Event object.
There is an AOP way to go about this,
AOP?

using apply, it is possible to invoke the fp with multiple arguments.
fp?

YUI made this decision early on and are stuck with it in the API.

Yahoo! code is not a showcase for good programming.
If you want to pass multiple arguments; Use an object.

It is a possibility to consider, but not necessarily the best one.
SpecialEvent = function SpecialEvent( domEvent, foo ) {
this.domEvent = domEvent;
this.foo = foo;
};

That is merely a property assignment, maybe a variable assignment.
And where would `domEvent' come from anyway?


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top