www.webdeveloper.com
Results 1 to 15 of 15

Thread: [RESOLVED] Use string as function name

  1. #1
    Join Date
    Dec 2010
    Posts
    232

    resolved [RESOLVED] Use string as function name

    I currently have a string which is retrieved from an element's data and stored in the variable "s".

    I want to set an onclick of a button using this string variable as the function name followed by "(this)" so for example if the string stored in s is "showText" the function would be "showText(this)"

    At the moment I apply the onclick to my button like this:-

    Code:
    b.onclick=function(){showText(this)};
    however it needs to be something along these lines to accept a string as the function name:-

    Code:
    b.onclick=function(){<S GOES HERE>(this)};
    Is this possible preferably without eval

  2. #2
    Join Date
    Nov 2010
    Posts
    1,087
    being that a function is an object available in the global scope (and provided that s is global as well), you can try this:

    b.onclick=function(){window[s](this)};

  3. #3
    Join Date
    Dec 2010
    Posts
    232
    Even with that I still can't get it working unfortunatley. What I'm trying to do is give everything that has onclicks a class that represents that onclick i.e. if I have an element that i want to assign the onlick functions showText(this) and openWindow(this) I will give them a class like this :-

    class="j_showText j_openWindow"

    That way I can loop through every element on the page checking if their class attribute contains "j_" and then if it does loop through every their classes and assign on clicks based on them. Here is what I have so far but it only seems to assign the very last onclick of the last item found to all elements that are clickable:-

    Code:
    function setClicks(){
    
    	ar=document.getElementsByTagName('*');//gets every element
    	
    	for(i=0;i<ar.length;i++){//loops through every element
    		if(ar[i].className.indexOf('j_')!=-1){//checks if element class contains "j_"
    			e=ar[i];//sets the element as the variable "e"		
    			cl=e.className.split(/\s+/);//gets all the classes of the elements and stores them in an array called "cl"
    			for (y=0;y<cl.length;y++){//loops through each class in cl
    			   if(cl[y].indexOf('j_')!=-1){//checks the class contains "j_"
    				  fn=window[cl[y].substring(2)];//creates the function name using the classname minus it's first two characters	 						
    				  e.onclick=function(){fn(this)};//sets the new function as the onclick of the element
    			   }
    			}			
    		}
    	}
    }

  4. #4
    Join Date
    Nov 2010
    Posts
    1,087
    classic closure problem. here's one way around it...

    Code:
    function setClicks(){
    
    	ar=document.getElementsByTagName('*');//gets every element
    	
    	for(i=0;i<ar.length;i++){//loops through every element
    		if(ar[i].className.indexOf('j_')!=-1){//checks if element class contains "j_"
    			e=ar[i];//sets the element as the variable "e"		
    			cl=e.className.split(/\s+/);//gets all the classes of the elements and stores them in an array called "cl"
    			for (y=0;y<cl.length;y++){//loops through each class in cl
    			   if(cl[y].indexOf('j_')!=-1){//checks the class contains "j_"
    				  fn=cl[y].substring(2);//creates the function name using the classname minus it's first two characters	
    				  e.onclick=(function(fn) { 
    							return function() {
    							window[fn](this)
    							}
    							})(fn);//sets the new function as the onclick of the element
    			   }
    			}
    		}
    	}
    }

  5. #5
    Join Date
    Dec 2010
    Posts
    232
    Thanks xelawho. I've changed my function to this:-

    Code:
    function setClicks(){
    
    	ar=document.getElementsByTagName('*');//gets every element
    	
    	for(i=0;i<ar.length;i++){//loops through every element
    		if(ar[i].className.indexOf('j_')!=-1){//checks if element class contains "j_"
    			e=ar[i];//sets the element as the variable "e"		
    			cl=e.className.split(/\s+/);//gets all the classes of the elements and stores them in an array called "cl"
    			for (y=0;y<cl.length;y++){//loops through each class in cl
    			   if(cl[y].indexOf('j_')!=-1){//checks the class contains "j_"
    				  fn=window[cl[y].substring(2)];//creates the function name using the classname minus it's first two characters	 						
    				  e.onclick=(function(fn){ 
    					return function(){
    						window[fn](this)
    					}})(fn);//sets the new function as the onclick of the element		   
    				}
    			}			
    		}
    	}
    }
    Unfortunately now when I click on one of the elements that the onclick is applied to nothing happens and I get this error:-

    Code:
    Uncaught TypeError: Property 'function showText(x){
    
    document.getElementById('text').style.display="block";
    
    }' of object [object DOMWindow] is not a function
    (anonymous function)
    Any ideas?

  6. #6
    Join Date
    Dec 2010
    Posts
    232
    Nevermind I missed a line but now it's working perfect. Bye bye inline javascript. Thanks

  7. #7
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,268
    A variant from Douglas Crowford (see this page) ?
    Code:
    Function.prototype.method = function (name, func) {
        this.prototype[name] = func;
        return this;
    };
    &#171;This adds a public method to the Function.prototype, so all functions get it by Class Augmentation. It takes a name and a function, and adds them to a function's prototype object&#187; !

  8. #8
    Join Date
    Nov 2010
    Posts
    1,087
    I assume there are easier ways to write unobtrusive javascript and people often assign event listeners in this way while overlooking the fact that it is often easier to use one function and pass it the correct arguments, but without seeing what OP is doing, it's hard to say what the best approach is.

    But in the end for the amount of hoops that need to be jumped through, I'm still unconvinced that unobtrusive javascript is the holy grail it's made out to be. Of course it has its place, but I don't think every piece of code needs to be written to its exacting standards just because of some abstract idea that it is "better"

  9. #9
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,268
    I am discovering these methods. It was only to open some perspectives ...
    Last edited by 007Julien; 04-19-2012 at 04:35 AM.

  10. #10
    Join Date
    Nov 2010
    Posts
    1,087
    of course. and new perspectives are always useful. I'm just saying that each approach has to be evaluated for its merits and how it applies to the situation at hand. once a dogma is established and every alternative is automaticaly discarded if it doesn't fit into that framework the thinking becomes sloppy.

    a little bit like life, really...

  11. #11
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,268
    &#171;Je pense donc je suis &#187;, (I think therefore I am or Cogito, ergo sum) said Ren&#233; Descartes !

  12. #12
    Join Date
    Dec 2010
    Posts
    232
    Thanks for the help guys. It works well although I now have another problem. Basically some of these clickable elements are going to be inside other clickable elements so I have also used a stopPropagation class so that any elements that have this class will have their event propagation stopped i.e. if they are inside another clickable element and are clicked their event will fire as opposed to the container elements click event. Here's my new code:-

    Code:
    function setClicks(){
    
    	ar=document.getElementsByTagName('*');//gets every element
    	
    	for(i=0;i<ar.length;i++){//loops through every element
    		if(ar[i].className.indexOf('j_')!=-1){//checks if element class contains "j_"
    			e=ar[i];//sets the element as the variable "e"		
    			cl=e.className.split(/\s+/);//gets all the classes of the elements and stores them in an array called "cl"
    			for (y=0;y<cl.length;y++){//loops through each class in cl
    			   if(cl[y].indexOf('j_')!=-1){//checks the class contains "j_"
    				  fn=cl[y].substring(2);//creates the function name using the classname minus it's first two characters	 						
    				  e.onclick=(function(fn){
    					return function(evt){
    						evt.stopPropagation;//stops propagation
    						window[fn](this);//assigns the function
    					}})(fn);//sets the new function as the onclick of the element		   
    				}
    			}			
    		}
    	}
    }
    This works in some cases such as when clicking a text box however the problem is when it is like this:-

    Code:
    <div class="j_functionA">
       <a href="" class="j_functionB">
          <span>Text part 1</span>
          <span>Text part 2</span>
       </a>
    </div>
    and the text inside the anchor tag (in the spans) is clicked, the outer divs click event fires whereas if I change it to this:-

    Code:
    <div class="j_functionA">
       <a href="" class="j_functionB">Text part 1 Text part 2</a>
    </div>
    Clicking the text inside the anchor tag fires function B correctly. Is there any way around this without assigning functionB to every element inside the anchor tag?

  13. #13
    Join Date
    Oct 2010
    Location
    Versailles, France
    Posts
    1,268
    See this page from Peter-Paul Koch about event order

  14. #14
    Join Date
    Dec 2010
    Posts
    232
    Cheers Julien. That's a good link, very informative and helps me understand but I can't seem to see anywhere which addresses my problem.

    The thing is the way I currently have it set up works AS LONG as I don't have spans inside my anchor tag as I described above however when I put them in (they are needed by the way) and the user clicks the anchor tag containing the spans it acts as if the spans themselves are being clicked and not the anchor tag which has the onclick event.

    How can I fix this in my above code, perhaps by looping through all the children of the element that is having the click event assigned to it and assigning it to them too? Seems like overkill to me.

  15. #15
    Join Date
    Dec 2010
    Posts
    232
    Still struggling with this specific problem at the moment if anyone can please help.

    I've noticed twitter use something similar like this:-

    Code:
    <span class="username js-action-profile-name">
       <s>@</s>
       <b>johnsmith</b>
    </span>
    When you click the above element a lightbox opens up showing the clicked user in detail. I assume this means that the onclick function is applied to the span whereas when I try the same thing the function doesn't fire for me and it acts as though the inner spans are being clicked rather than the outer one

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles