passing the string-name of the function to addEvent

S

simon

hi,

I would like to separate my javascript completely from my xhtml. in the
end there should be only
<script type="text/javascript" src="javalib.js"></script>
in the head-tag to my javascript.

Because I want to use some ajax-requests and other javascript-functions
on my xhtml, I need to dynamically add event handlers to any possible
dom-elements. All solutions I found so fare are for specific, pre-known
dom-elements: like 'all <img> of a certain <span>-class get an
onmouseover event handler'. But I need a function, which runs onload of
the window and dynamically determines, which dom-elments need an event
handler and which ones don't.
So I guessed the best way would be to traverse the whole dom-tree
looking for certain id-attributes, which would indicate the browser,
that the according dom-element (having the certain id-attribute) needs
to have an event added.
Therefore I defined my id-attributes with a pattern like eg. <span
id="onclick_helloworld_param1_param2"></span> what means, that the
value of the id attribute first needs to provide the name of an event
handler, this way javascript can determine that this dom-element is an
element, which needs to have an event-handler. Then javascript can
parse the value of the id-attribute with the function split('_');
With the above example this results in an array containing:
[0] 'onclick' //the event-handler
[1] 'helloworld' //the function to be called
[2] 'param1'
... ..
[n] 'paramn' //the parameters for the function to be called.

so far all good, but now I'm stuck with the following problem: I got
the name of the function as a String and don't know how to make
javascript understand that this string points to an actual function,
like:

function helloworld(param1, param2, ... , paramn){
alert(param1);
}

I guess it all comes down to the following question: I'm trying to use
the 'famous' function addEvent(). What do I need to do just having name
of fn as a string, and want to pass the parameters to fn too?

//this is what I tried the latest, but it obviously does not work...
n = some dom-element;
eve = 'click';
var newfunct = new Function(param1, param2);
newfunct.name = 'helloworld';
addEvent(n, eve, newfunct, false);

function addEvent(elm, evType, fn, useCapture) {
if (elm.addEventListener) {
elm.addEventListener(evType, fn, useCapture);
return true;
}
else if (elm.attachEvent) {
var r = elm.attachEvent('on' + evType, fn);
return r;
}
else {
elm['on' + evType] = fn;
}
}

thanks for any help or other ideas to solve the problem of dynamically
add event handlers to any possible dom-elments.

s
 
R

Randy Webb

simon said the following on 12/14/2006 5:51 PM:
hi,

I would like to separate my javascript completely from my xhtml. in the
end there should be only
<script type="text/javascript" src="javalib.js"></script>
in the head-tag to my javascript.

Because I want to use some ajax-requests and other javascript-functions
on my xhtml, I need to dynamically add event handlers to any possible
dom-elements. All solutions I found so fare are for specific, pre-known
dom-elements: like 'all <img> of a certain <span>-class get an
onmouseover event handler'. But I need a function, which runs onload of
the window and dynamically determines, which dom-elments need an event
handler and which ones don't.
So I guessed the best way would be to traverse the whole dom-tree
looking for certain id-attributes, which would indicate the browser,
that the according dom-element (having the certain id-attribute) needs
to have an event added.
Therefore I defined my id-attributes with a pattern like eg. <span
id="onclick_helloworld_param1_param2"></span> what means, that the
value of the id attribute first needs to provide the name of an event
handler, this way javascript can determine that this dom-element is an
element, which needs to have an event-handler. Then javascript can
parse the value of the id-attribute with the function split('_');
With the above example this results in an array containing:
[0] 'onclick' //the event-handler
[1] 'helloworld' //the function to be called
[2] 'param1'
.. ..
[n] 'paramn' //the parameters for the function to be called.

theArray = attr.split('_');

Set up a case/switch for the different handlers. Then in each case block
you deal with that:

elemRef.onclick=window[theArray[1]](theArray[2],theArray[3]);

All global functions are properties of the window object in any decently
implemented browser (that includes IE as well).
 
R

RobG

simon said:
hi,

I would like to separate my javascript completely from my xhtml. in the
end there should be only
<script type="text/javascript" src="javalib.js"></script>
in the head-tag to my javascript. [...]
Therefore I defined my id-attributes with a pattern like eg. <span
id="onclick_helloworld_param1_param2"></span> what means, that the

I think you need to prefix that with a real id to guarantee unique IDs.
Also consider putting the parameter part in the class attribute so you
don't trash your IDs this way.
value of the id attribute first needs to provide the name of an event
handler, this way javascript can determine that this dom-element is an
element, which needs to have an event-handler. Then javascript can
parse the value of the id-attribute with the function split('_');
With the above example this results in an array containing:
[0] 'onclick' //the event-handler
[1] 'helloworld' //the function to be called
[2] 'param1'
.. ..
[n] 'paramn' //the parameters for the function to be called.

so far all good, but now I'm stuck with the following problem: I got
the name of the function as a String and don't know how to make
javascript understand that this string points to an actual function,
like:

function helloworld(param1, param2, ... , paramn){
alert(param1);
}


Given that param[1] is the string 'helloworld' then:

window[param[1]]();

will call the helloworld function. Consider name spacing your
functions.

I guess it all comes down to the following question: I'm trying to use
the 'famous' function addEvent(). What do I need to do just having name
of fn as a string, and want to pass the parameters to fn too?

//this is what I tried the latest, but it obviously does not work...
n = some dom-element;
eve = 'click';
var newfunct = new Function(param1, param2);

Ditch that, new Function() is considered only marginally better than
eval.
newfunct.name = 'helloworld';

var newfunct = window[param[1]];
addEvent(n, eve, newfunct, false);

And how do you pass the parameters? I'd suggest that you use shift()
to get the first few parameters, then pass the remainder of the
parameter array to the function using apply, see below.

The apply method (which uses an array as the set of arguments) also
lets you set the value of the function's this keyword appropriately (IE
and Gecko event models differ here, apply makes them consistent).

e.g.

<script type="text/javascript">

function processId(el){
var params = el.className.split('_');
if (params.length > 1){
var evt = params.shift();
var fn = params.shift();
addEvent(el, evt,
function(){window[fn].apply(el, params)}, false);
}
}

function addEvent(elm, evType, fn, useCapture) {
if (elm.addEventListener) {
elm.addEventListener(evType, fn, useCapture);
return true;
}
else if (elm.attachEvent) {
var r = elm.attachEvent('on' + evType, fn);
return r;
}
else {
elm['on' + evType] = fn;
}
}

window.onload = function(){
processId(document.getElementById('xx'));
processId(document.getElementById('yy'));
}

function hi(args){
alert('id: ' + this.id
+ '\nparams: ' + args);
}

</script>


<div id="xx" class="click_hi_x1_x2">xx</div>
<div id="yy" class="click_hi_y1_y2">yy</div>


Notes:

The parameters are passed as strings, if you want them to be something
else, you'll have to deal with that in the processId() function.

If you want to have real class names in the class attribute, you'll
have to include a scheme to find your parameter class name in amongst
the other class names.

You may be tempted to use a getElementsByClassName function to find
your special elements and process their special class attribute.

Consider removing the extra attribute values when you've finished with
them if you have other processing of the class attribute to do. It
might also help the browser if there is less junk in the attribute.
 
S

simon

thanks for your help!

in the meanwhile I could arrange my code to work by myself. I will
check it with your suggestions.
to be sure that the id remains unique i will add a incremental value to
it at its end.
the following has been tested on safari, firefox and iex. works for
ajax-requests too just recalling traverseTags(ajaxresponse).
if you just can shake your head and get bad headaches upon this
solution don't hesitate to let me know!! ;)

<script type="text/javascript">

this.onload = init;

function sali (e){
alert('done' + this.params.toString());
}

function hoi(e){
alert('done' + this.params.toString());
}

//returns function for a function string
function getFunction(functionstr){
if(functionstr == 'sali'){
return sali;//function sali
}
else if(functionstr == 'hoi'){
return hoi;//function hoi
}
else{
return false;
}
//etc.
}

function init(){
traverseTags(document);
}


//if some browser does not know the Node object
if (!window.Node) {
var Node = { // If there is no Node object, define one
ELEMENT_NODE: 1, // with the following properties and values.
ATTRIBUTE_NODE: 2, // Note that these are HTML node types only.
TEXT_NODE: 3, // For XML-specific nodes, you need to add
COMMENT_NODE: 8, // other constants here.
DOCUMENT_NODE: 9,
DOCUMENT_FRAGMENT_NODE: 11
}
}

//stores all possible events
var arrEvents = new Array('onclick', 'ondblclick', 'onmousedown',
'onmouseup', 'onmouseover', 'onmousemove', 'onmouseout', 'onkeypress',
'onkeydown', 'onkeyup');

//array function to check for a certain value in an array. call:
array.contains(value)
Array.prototype.contains = function(value) {
for (var i = 0; i < this.length; i++) {
if (this == value) return true;
}
return false;
}

//traversing the tags i thereby could assign the function name:
function traverseTags(n){
var children = n.childNodes;
if(n.nodeType == Node.ELEMENT_NODE && n.attributes.length > 0){
for(var i = 0; i < n.attributes.length; i++){

if(n.attributes.nodeName == 'id' &&
isEventTag(n.attributes.nodeValue)){// && n.hasAttributes() not iex
var call = new
callerObject(isEventTag(n.attributes.nodeValue));
var eve = call.getEvent();

var funct = call.getFunction();

var params = call.getParams();

addEvent(n, eve, getFunction(funct), false);//needs to be an
addEvent function which contains the this reference for iex.
n.params = params;
break;
}
}
}

for(var i=0; i < children.length; i++) { // Loop through the
children
traverseTags(children);
}
}


//checks if the id attribute is a event
function isEventTag(idAttribute){
var spliter = idAttribute.split('_');//spliter is the array with all
parameters form the id attribute: e.g.
onclick_somefunction_sometag_param1_param2_param3
if(arrEvents.contains(spliter[0])) return spliter;
return false;
}




//parses the array
function callerObject(callerArray){
var event = callerArray[0];//der event
var funct = callerArray[1];//die function
var callback_obj = null;
var paramArray = new Array();
for(var i = 0; i < callerArray.length-2; i++){
paramArray = callerArray[i+2];
}

this.getFunction = function(){
return funct;// Function(funct + '(' + paramArray.toString() +
');');
}

this.getParams = function(){
return paramArray;
}

this.getEvent = function(){
return getEventOfString(event);
}

function getEventOfString(eventstr){//private
if(eventstr == 'onclick'){
return 'click';
}
else if(eventstr == 'ondblclick'){
return 'dblclick';
}
else if(eventstr == 'onmousedown'){
return 'mousedown';
}
else if(eventstr == 'onmouseup'){
return 'mouseup';
}
else if(eventstr == 'onmouseover'){
return 'mouseover';
}
else if(eventstr == 'onmousemove'){
return 'mousemove';
}
else if(eventstr == 'onkeypress'){
return 'keypress';
}
else if(eventstr == 'onkeydown'){
return 'keydown';
}
else if(eventstr == 'onkeyup'){
return 'keyup';
}
else{
return false;
}
}
}





// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini

// http://dean.edwards.name/weblog/2005/10/add-event/

function addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
// assign each event handler a unique ID
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
// create a hash table of event types for the element
if (!element.events) element.events = {};
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one)
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};
// a counter used to create unique IDs
addEvent.guid = 1;

function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};

function handleEvent(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(((this.ownerDocument || this.document ||
this).parentWindow || window).event);
// get a reference to the hash table of event handlers
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
this.$$handleEvent = handlers;
if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};

function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
};

</script>


<a href="index1.html" id="onclick_hoi_index2.html">click me to
replace1</a><br/>
<a href="index2.html" id="onclick_sali_index.html_2">click me to
replace2</a><br/>
<a href="index3.html" id="onclick_sali_index.html_3">click me to
replace3</a><br/>
<a href="index4.html" id="onclick_sali_index.html_4">click me to
replace4</a><br/>
<a href="index5.html" id="onclick_sali_index.html_5">click me to
replace5</a><br/>
 
D

Dr J R Stockton

In comp.lang.javascript message
Fri said:
function getEventOfString(eventstr){//private
if(eventstr == 'onclick'){
return 'click';
}
else if(eventstr == 'ondblclick'){
return 'dblclick';
}
else if(eventstr == 'onmousedown'){
return 'mousedown';
}
else if(eventstr == 'onmouseup'){
return 'mouseup';
}
else if(eventstr == 'onmouseover'){
return 'mouseover';
}
else if(eventstr == 'onmousemove'){
return 'mousemove';
}
else if(eventstr == 'onkeypress'){
return 'keypress';
}
else if(eventstr == 'onkeydown'){
return 'keydown';
}
else if(eventstr == 'onkeyup'){
return 'keyup';
}
else{
return false;
}
}

If all good eventstr start with "on" and the rest must be returned, else
false, then

function XX(es) { var T
return ( ( (T = es.replace(/^on/, "")) ) != es ) && T }

could be used. But it accepts anything after "on" (though it could
easily be modified to accept only letters, and only 5-9 of those.

It's a good idea to read the newsgroup and its FAQ. See below.
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top