SitePoint Sponsor

User Tag List

Results 1 to 5 of 5
  1. #1
    SitePoint Enthusiast
    Join Date
    Sep 2007
    Location
    Newcastle, UK
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Dynamic onclick function

    Hi, I am having a little problem here and hope someone can help! I am trying to assign onclick events to dynamically created links, however each link has the same ID - to make that understandable..

    I have this XML response..

    Code:
    ...
    <subCategoryList>
    	<subCategoryId>1</subCategoryId>
    	<subCategoryName>Name 1</subCategoryName>
    	<subCategoryId>2</subCategoryId>
    	<subCategoryName>Name 2</subCategoryName>
    	<subCategoryId>3</subCategoryId>
    	<subCategoryName>Name 3</subCategoryName>
    ...
    	<subCategoryId>X</subCategoryId>
    	<subCategoryName>Name 4</subCategoryName>
    </subCategoryList>
    ...
    And the Javascript:

    Code:
    ...
    var subCategoryIdList = response.getElementsByTagName('subCategoryId');
    var subCategoryNameList = response.getElementsByTagName('subCategoryName');
    var secondLevelContainer = document.getElementById("subLevelCategoryContainer");
    ...
    // Add each sub category to the div
    for(var i=0;i<subCategoryIdList.length;i++) {
    	var tempDiv	 = document.createElement("div");
    	var tempLink = document.createElement("a");
    	var subCatId 	= subCategoryIdList[i].firstChild.nodeValue;
    	var subCatName 	= subCategoryNameList[i].firstChild.nodeValue;
    	
    	// Style the div
    	tempDiv.className = "upgradeViewMenuItem";
    	
    	// Make the link
    	tempLink.innerHTML 	= subCatName;
    	tempLink.href		= "#";
    	tempLink.onclick	= function() { makeRequest("UpgradeViewAjax.php?subCategory=" + subCatId); }
    		
    	// Add link to the div
    	tempDiv.appendChild(tempLink);
    	
    	// Add the div to the container
    	secondLevelContainer.appendChild(tempDiv);
    }
    Now what I expected to get out was x amount of links with:

    Code:
    onclick="UpgradeViewAjax.php?subCategory=1"
    onclick="UpgradeViewAjax.php?subCategory=2"
    onclick="UpgradeViewAjax.php?subCategory=3"
    ...
    onclick="UpgradeViewAjax.php?subCategory=X"
    However what I am getting is:

    Code:
    onclick="UpgradeViewAjax.php?subCategory=X"
    onclick="UpgradeViewAjax.php?subCategory=X"
    onclick="UpgradeViewAjax.php?subCategory=X"
    ...
    onclick="UpgradeViewAjax.php?subCategory=X"
    i.e. The onclick is only using the FINAL id. The subCatId variable though IS changing on each iteration (so doing alert(subCatId) results in 1,2,3,...,X) - this looks like a scope issue but I'm not really sure how to fix it - any ideas?

  2. #2
    SitePoint Evangelist
    Join Date
    Jul 2007
    Posts
    345
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You're right, it's a scope (and closure) issue and is a very common problem in JavaScript.

    The onclick function maintains a reference to the subCatId variable. When the onclick function is called, at some point in the future, it will use the value of subCatId at that time, which will be whatever the last value in the loop was.

    To fix the problem, set a new scope by wrapping your code in another function:
    Code:
    for(var i=0;i<subCategoryIdList.length;i++) {
      (function(i){
    	var tempDiv	 = document.createElement("div");
    	var tempLink = document.createElement("a");
    	var subCatId 	= subCategoryIdList[i].firstChild.nodeValue;
    	var subCatName 	= subCategoryNameList[i].firstChild.nodeValue;
    	
    	// Style the div
    	tempDiv.className = "upgradeViewMenuItem";
    	
    	// Make the link
    	tempLink.innerHTML 	= subCatName;
    	tempLink.href		= "#";
    	tempLink.onclick	= function() { makeRequest("UpgradeViewAjax.php?subCategory=" + subCatId); }
    		
    	// Add link to the div
    	tempDiv.appendChild(tempLink);
    	
    	// Add the div to the container
    	secondLevelContainer.appendChild(tempDiv);
      })(i);
    }
    Take a look at http://www.room51.co.uk/js/closures.html for a discussion of why this works.

  3. #3
    SitePoint Enthusiast
    Join Date
    Sep 2007
    Location
    Newcastle, UK
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That works a treat, thanks a lot!
    One Stop Dive - The only scuba diving stop you need to make!

  4. #4
    SitePoint Enthusiast
    Join Date
    Sep 2007
    Location
    Newcastle, UK
    Posts
    27
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi, along the same lines I am having the same problem without the loop I have a function:

    Code:
    function foo() {
        if (undefined===foo.count) {
            foo.count= 0;
        } else {
    	foo.count++;
        }
    
    ...
    
    deleteLink.onclick = function() { anotherFunction(foo.count); }
    }
    with the predictable outcome that each deleteLink will have the final value of foo.count!

    I have read the room51 article a dozen times and still can't figure it out properly - could someone tell me the quick fix for this problem please - I will try and understand it later!
    One Stop Dive - The only scuba diving stop you need to make!

  5. #5
    SitePoint Evangelist
    Join Date
    Jul 2007
    Posts
    345
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    (function(count){
      deleteLink.onclick = function() {anotherFunction(count);};
    })(foo.count);


Bookmarks

Posting Permissions

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