passing the string-name of the function to addEvent

Discussion in 'Javascript' started by simon, Dec 14, 2006.

  1. simon

    simon Guest

    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
    simon, Dec 14, 2006
    #1
    1. Advertising

  2. simon

    Randy Webb Guest

    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).

    --
    Randy
    Chance Favors The Prepared Mind
    comp.lang.javascript FAQ - http://jibbering.com/faq
    Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
    Randy Webb, Dec 15, 2006
    #2
    1. Advertising

  3. simon

    RobG Guest

    simon wrote:
    > 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.


    --
    Rob
    RobG, Dec 15, 2006
    #3
  4. simon

    simon Guest

    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/>
    simon, Dec 15, 2006
    #4
  5. In comp.lang.javascript message
    <>, Fri, 15 Dec 2006
    06:09:41, simon <> wrote:

    > 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.

    --
    (c) John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v6.05 IE 6
    <URL:http://www.jibbering.com/faq/> A FAQ for news:comp.lang.javascript.
    <URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
    <URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
    Dr J R Stockton, Dec 15, 2006
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. cutecutemouse
    Replies:
    2
    Views:
    346
    cutecutemouse
    Jul 13, 2008
  2. kaeli

    addEventHandler / addEvent conflict

    kaeli, Jan 14, 2004, in forum: Javascript
    Replies:
    4
    Views:
    165
    kaeli
    Jan 14, 2004
  3. Replies:
    3
    Views:
    161
  4. Aaron Gray

    addEvent - The late entry :)

    Aaron Gray, Jul 16, 2008, in forum: Javascript
    Replies:
    64
    Views:
    891
    dhtml
    Aug 31, 2008
  5. Richard Maher

    IE leaks, circular references, addevent et al

    Richard Maher, Sep 15, 2009, in forum: Javascript
    Replies:
    30
    Views:
    408
    David Mark
    Sep 29, 2009
Loading...

Share This Page