469,304 Members | 1,888 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,304 developers. It's quick & easy.

How to add extra action to onclick event ?

abs
My element:
<span onclick="alert('test')" id="mySpan">test</span>

Let's say that I don't know what is in this span's onclick event. Is it
possible to add another action to this element's onclick event ? I've tried
something like this:

oncl = document.getElementById('mySpan').onclick
oncl = oncl + '\n;alert(\'added\')'
document.getElementById('mySpan').onclick = oncl

And after this operation there'e no reaction to clicking on the <span>.
Anybody knows how to fix it ?

Best regards,
ABS


Jul 23 '05 #1
17 4534
alu

"abs" <no****@wp.pl> wrote in message news:d7**********@inews.gazeta.pl...
My element:
<span onclick="alert('test')" id="mySpan">test</span>

Let's say that I don't know what is in this span's onclick event. Is it
possible to add another action to this element's onclick event ? I've tried something like this:

oncl = document.getElementById('mySpan').onclick
oncl = oncl + '\n;alert(\'added\')'
document.getElementById('mySpan').onclick = oncl

And after this operation there'e no reaction to clicking on the <span>.
Anybody knows how to fix it ?

Best regards,
ABS

I'm probably misunderstanding the problem, but it would seem easier
to set onclick to a function, then add lines to the -function- dynamically.

<scr ipt>
function mySpanClicked(){
alert("test");
}
</scr ipt>

<span onclick="mySpanClicked()" id="mySpan">test</span>

<scr ipt>
.... script to add to mySpanClicked()
</scr ipt>

-alu
Jul 23 '05 #2
You cant just add another action to the onClick event, but you may find
this handy....

<span onclick="alert('test');alert('second function')"
id="mySpan">test</span>

This will now call the 2 actions one after the other. note the
semi-colon in there after the first event.

You can repeat that more to add extra actions.

Best Regards,
Sandfordc

Jul 23 '05 #3
On 26/05/2005 20:32, abs wrote:
My element:
<span onclick="alert('test')" id="mySpan">test</span>

Let's say that I don't know what is in this span's onclick event. Is it
possible to add another action to this element's onclick event ?
The code at the end of this post is a very generic way of adding and
removing listeners from an element, much in the same way as the
addEventListener method.

Though the code looks daunting, a lot of it is internal. For basic
usage, you need only three methods:

DispatcherFactory.createDispatcher()

This creates and returns a dispatcher object. Each dispatcher
maintains a list of listeners that are associated with a type
of event. When the dispatcher is attached to an element, it
forwards all events of this type to the listeners it manages.

The other two important methods are members of the dispatcher objects
returned by createDispatcher.

Dispatcher.add(listener)

This method adds a function to the internal list. Simple.
Dispatcher.attach(element, type)

This methods associates the dispatcher with a particular
event type, such as the click event, and a particular element.
If a listener already exists on that element for that type (an
onclick attribute, for example), it will be added to the
internal list before the dispatcher is attached.

So, given:

<span id="mySpan" onclick="alert('original');">Test</span>

and a reference to that element:

var element = document.getElementById('mySpan');

you can add a new function with:

var dispatcher = DispatcherFactory.createDispatcher();

dispatcher.add(function() {
alert('added');
});
dispatcher.attach(element, 'onclick');

You can call add and attach in any order, and you can add listeners at
any time. You can also attach the same dispatcher to several different
elements with different types, though I doubt you'll have any use for that.

The other two methods you can use are again dispatcher members.

Dispatcher.remove(listener)

This searches for the given function. If it exists within the
list, it's discarded.
Dispatcher.detach(element, type)

This removes the dispatcher and all of its listeners of the
given type from the element.
There are simpler solutions, but they aren't as flexible. It's
incredibly late now, so someone else will have to continue with those
alternatives.
oncl = document.getElementById('mySpan').onclick
oncl = oncl + '\n;alert(\'added\')'
document.getElementById('mySpan').onclick = oncl


There's a misconception here: the onclick property isn't a string. When
a user agent parses attributes like onclick in HTML, it converts the
code to a function. So, it's not simply a matter of added more code. The
dispatcher object below allows you to manage several functions on one
property.

Do ask if you have any questions.

Mike
Parts of the code below can be removed. If you won't be removing
listeners, you can eliminate the two remove methods (in Node and
createDispatcher), the detachDispatcher function, and the line:

Dispatcher.detach = detachDispatcher;

The code at the very end emulates the call method that should exist on
all functions. JScript versions prior to 5.5 (and so usually IE versions
prior to 5.5) don't include this method so a substitute needs to be
included. The dispatcher code only needs case 1 within the switch
statement, so you could remove the other clauses. They were included to
make the substitute more useful.

var DispatcherFactory = (function(global) {
function Node(data) {
var next = null;

this.fire = function(element, event) {
var performDefault = next
? next.fire(element, event)
: true;

return data.call(element, event) && performDefault;
};

this.add = function(listener) {
if(data == listener) {return;}

if(next) {
next.add(listener);
} else {
next = new Node(listener);
}
};
this.remove = function(listener) {
if(data == listener) {
return next;
} else if(next) {
next = next.remove(listener);
}
return this;
};
}

function attachDispatcher(element, type) {
var listener = element[type];

if(('function' == typeof listener)
&& (this.constructor != listener.constructor))
{
this.add(listener);
}
element[type] = this;
}
function detachDispatcher(element, type) {
if(this == element[type]) {
element[type] = null;
}
}

return {
createDispatcher : function() {
var list = null;

function Dispatcher(event) {
return list
? list.fire(this, event || global.event)
: true;
}
}
Dispatcher.constructor = this;

Dispatcher.add = function(listener) {
if(list) {
list.add(listener);
} else {
list = new Node(listener);
}
};
Dispatcher.remove = function(listener) {
if(list) {
list = list.remove(listener);
}
};

Dispatcher.attach = attachDispatcher;
Dispatcher.detach = detachDispatcher;
}
};
})(this);

if('function' != typeof Function.prototype.call) {
Function.prototype.call = function(object) {
var property = '__call', result, undef;

while('undefined' != typeof object[property]) {
property = '__' + property;
}
object[property] = this;

switch(arguments.length - 1) {
case 0:
result = object[property]();
break;
case 1:
result = object[property](arguments[1]);
break;
case 2:
result = object[property](arguments[1], arguments[2]);
break;
case 3:
result = object[property](arguments[1], arguments[2],
arguments[3]);
break;
case 4:
result = object[property](arguments[1], arguments[2],
arguments[3], arguments[4]);
break;
case 5:
result = object[property](arguments[1], arguments[2],
arguments[3], arguments[4], arguments[5]);
break;
default: alert('Too many arguments!');
}
object[property] = undef;

return result;
};
}

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #4
On 27/05/2005 03:26, Michael Winter wrote:

[snip]
function Dispatcher(event) {
return list
? list.fire(this, event || global.event)
: true;
}

^
I don't know where that closing brace came from, but it shouldn't be there.

I'll make the disclaimer now: this code is untested, and will remain so
until I wake up tomorrow. I don't think there are any more problems, but
I'm too tired to make any kind of guarantee.

Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #5
abs
Michael Winter wrote:
I'll make the disclaimer now: this code is untested, and will remain
so until I wake up tomorrow. I don't think there are any more
problems, but I'm too tired to make any kind of guarantee.


First, thank you so much for your post containing so lot of knowledge.
I've got one problem with that: when I call:

dispatcher.add(function() {
alert('added');
});

Firefox, throws an error: 'dispatcher has no properties'. I'm trying to fix
it by myself, but until now I couldn't see any mistakes in the code.

Best regards,
ABS
Jul 23 '05 #6
abs
alu wrote:
I'm probably misunderstanding the problem, but it would seem easier
to set onclick to a function, then add lines to the -function-
dynamically.


Thanks, but it's impossible. This is a part of bigger project and it has to
be universal, I don't even know the name of the function of onclick.

Regards,
ABS
Jul 23 '05 #7
abs
And another question: will I be able to pass the parameter to added function
?

ABS
Jul 23 '05 #8
VK
var success = (window.addEventListener)?
someObject.addEventListener('click',
functionPointer, false) :
someObject.attachEvent('onclick',
functionPointer);

You can add/attach any amount of functions to any object. Three points
to pay attention to:

1. With multiple event handlers each event handler will be called in a
random order (so you don't know which one will be called 1st, 2nd, 3rd,
n-th)

2. attachEvent in IE requires function pointer as its argument, so you
cannot use anonymous function declaration instead. You can bypass it by
doing:
var newFun = new Function(...);
someObject.attachEvent('onclick', newFun);

3. in IE event names are always "onevent" (starts with "on"). In FF a
semi-philologic approach is chosen, so
obj.onevent = (with "on") but addEventListener('event'...) (without
"on") Not really a problem but easy to mistype.

If you really need to call handlers in a fixed sequence (kinda
pointless because native JavaScript does not have synchronized methods)
you may use a function wrapper:
var newFun = new Function("method1; method2; method3;...");
var success = (window.addEventListener)?
someObject.addEventListener('click', newFun,
false) :
someObject.attachEvent('onclick', newFun);

Jul 23 '05 #9
VK wrote:
var success = (window.addEventListener)?
someObject.addEventListener('click',
The W3C events DOM - addEventListener - method is specified as a
property of Node objects. The - window - is not a Node object and so is
not specified as having such a property, and in some environments
supporting the events DOM the window does not have such a method. The
obviously correct test to use in this context is the test that has a
one-to-one relationship with the action to be taken; -
(someObj.addEventListener)?someObject.addEventList ener -.
functionPointer, false) :
someObject.attachEvent('onclick',
Not all browsers that do not implement a - window.addEventListener -
method implement an - attachEvent - method on elements. Indeed I can
only think of two that do. In the absence of such a method this code
would error-out with the call to a non-existent method, which is pretty
poor scripting.

<snip> 2. attachEvent in IE requires function pointer as its
argument, so you cannot use anonymous function declaration
instead.
There is no such thing as an 'anonymous function declaration'; the
function name Identifier is not optional in a function declaration.
You can bypass it by doing:
var newFun = new Function(...);
someObject.attachEvent('onclick', newFun);

<snip>

Bypass what? A function object is a function object regardless of how it
is created.

Richard.
Jul 23 '05 #10
VK
> Bypass what?

I thought you couldn't do like obj.attachEvent('onclick',
function(){alert('Click!');})
But my test case appeared to be broken, it works, so sorry.

Jul 23 '05 #11
VK
I guess

foo = (arr[i].addEventListener)?
arr[i].addEventListener('click', extra, false) :
arr[i].attachEvent('onclick', extra);

(where 'extra' is your function) would be enough in any context and no
problem with passing argument.

You have to remember that intrinsic handlers (<elm onevent="...") have
priority over programmed ones, so the function call goes like this:
1. intrinsic handlers
2. programmed handlers in random order (actually, this is the same
"organized disorder" as with key/value pairs in hash)

If you want to extend functionality based on the content of the
intrinsic handler, you may write an "EventStealer" though it has more
relation to hacking rather than to development:

....
var objRef = e.target || event.srcElement;
var evtType = (e.type)? e.type : event.type;
var funRef = objRef['on'+evtType];
alert("On " + evtType + " this "+ objRef.tagName + " does this:\n\n" +
funRef.toString();)
objRef['on'+evtType] = null;
alert("And now it does not!");

The code above is useless as it is, but you may study the function body
using RegExp and recompile it based on the study results.

Jul 23 '05 #12
On 27/05/2005 07:17, abs wrote:

The problem with the code as posted is that createDispatcher doesn't
actually return anything. I apologise.

After the line:

Dispatcher.detach = detachDispatcher;

add:

return Dispatcher;

After that it 'works', but I'll be happier once I perform more tests.
And another question: will I be able to pass the parameter to added function
?


I'm afraid not, but that's how the event model itself works. The
function you pass to the add method will always receive one argument:
the event object. The difference between this and using the event
attributes in HTML is that the user agent creates this outer function
for you. However, you can easily call other functions within the
listener (just like alert in the example), passing any arguments you like.

Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #13
abs
Thank you guys for your posts. You helped me much.

ABS
Jul 23 '05 #14
VK wrote:
I guess

foo = (arr[i].addEventListener)?
arr[i].addEventListener('click', extra, false) :
arr[i].attachEvent('onclick', extra);

(where 'extra' is your function) would be enough in any
context and no problem with passing argument.
Except on browsers that support neither mechanism, where the call to the
non-existent - attachEvent - method errors and kicks the code out of
execution.

<snip> var objRef = e.target || event.srcElement;
var evtType = (e.type)? e.type : event.type;
If - e - was not defined evaluating the expression - e.type - would
produce an error (again). It makes more sense to normalise the event
object once with - e = e || window.event -(and the like) and then act
only on that normalised event object.
var funRef = objRef['on'+evtType];
alert("On " + evtType + " this "+ objRef.tagName +
" does this:\n\n" + funRef.toString();)
objRef['on'+evtType] = null;
alert("And now it does not!");

The code above is useless as it is,
Absolutly.
but you may study the function body using
RegExp and recompile it based on the study results.


The - toString - method of functions is specified as producing an
"implementation dependent" string. That string does not necessarily
correspond with the function's source code, and cannot necessarily be
re-interpreted as a functionally equivalent function. I.E. This strategy
should be expected to fail, and it certainly will in known existing
environments under some circumstances.

Richard.
Jul 23 '05 #15
On 27/05/2005 12:20, Richard Cornford wrote:

[snip]
The - toString - method of functions is specified as producing an
"implementation dependent" string. That string does not necessarily
correspond with the function's source code,
Maybe, but I'd think not. After the specification states that "An
implementation-dependent representation of the function is returned", it
goes on to say that "This representation has the syntax of a
FunctionDeclaration."

My interpretation is that the returned value should correspond with the
source code, but that the "placement of white space, line terminators,
and semicolons within the representation string is
implementation-dependent."

Of course, what should happen and what does happen in practice isn't
always the same.
and cannot necessarily be re-interpreted as a functionally equivalent
function.


Very true. There may be no way to reconstruct the scope chain, which may
render the function completely useless.

[snip]

Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #16
Michael Winter wrote:
On 27/05/2005 12:20, Richard Cornford wrote: <snip>
The - toString - method of functions is specified as
producing an "implementation dependent" string. That
string does not necessarily correspond with the
function's source code,

<snip> it goes on to say that "This representation has the syntax
of a FunctionDeclaration." <snip> Of course, what should happen and what does happen
in practice isn't always the same.

<snip>

Yes, regular expression literals within function bodies have proved a
recurrent problem in this context because they are independently
interpreted into regular expression objects. It is not unusual to find a
regular expression object in a toString-ed function coming out as
[Object], or something similar. Which is a syntactically fine expression
in a regular expression literal context (being an array literal with one
element referring to the Object constructor), but will certainly not
produce the original functionality.

Chopping up function body strings and re-assembling the results has been
tired, but all that I have observed trying it (at least those that
actually test their code more than superficially) seem to rapidly
abandon the idea in favour of accumulating function references in the
type of code you presented.

Richard.
Jul 23 '05 #17
VK wrote:
Bypass what?


I thought you couldn't do like obj.attachEvent('onclick',
function(){alert('Click!');})
But my test case appeared to be broken, it works, so sorry.


No. You both can and cannot use this. It depends on the JScript version
available on the client whether function expressions are considered a
syntax error or not. With new IEs, chances are high that it works.
PointedEars
--
Let us not judge others because of their religion, color or nationality.
We are all just human beings living together on this planet. (poehoe.de)
Jul 23 '05 #18

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

17 posts views Thread by Mike Gratee | last post: by
2 posts views Thread by Vinita Sharma | last post: by
3 posts views Thread by f1crazed | last post: by
5 posts views Thread by Stuart Shay | last post: by
3 posts views Thread by Michael_R_Banks | last post: by
6 posts views Thread by Nathan Sokalski | last post: by
1 post views Thread by CARIGAR | last post: by
1 post views Thread by Geralt96 | last post: by
reply views Thread by harlem98 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.