www.webdeveloper.com
Results 1 to 7 of 7

Thread: Weird Error with Variable Contents

Hybrid View

  1. #1
    Join Date
    Jul 2011
    Posts
    54

    Weird Error with Variable Contents

    I am having a bit of trouble with a function I am trying to debug.

    The function is supposed to load a bunch of mouseover events for various elements in the page and display information about a province/region in a div when that province/region is moused over.

    Here is the code I am using, (I know that this code is poorly written, by logically I don't see why it doesn't work):

    Code:
    function provInfoBox()
    {						
    	$(document).ready(function()
    	{			
    		for(var i = 2; i <= 11; i++)
    		{
    			var data = provData[i].split(",");
    			var provName = data[0];
    			var provRate = data[dateVal];
    			var str = "Rural " + provName + ": " + provRate + '%';
    
    			switch(i)
    			{
    				case 2:
    				{
    					for(var j = 1; j <= 5; j++) 
    					{
    						document.getElementById('Newfoundland and Labrador ' + j).addEventListener('mouseover', function() {return ieTip(str)}, false );
    						document.getElementById('Newfoundland and Labrador ' + j).addEventListener('mouseout', clearTipIE, false );
    					}							
    					break;	
    				}
    							
    				...
    							
    				case 11:
    				{
    					for(var j = 1; j <= 6; j++)
    					{
    						document.getElementById('British Columbia ' + j).addEventListener('mouseover', function() {return ieTip(str)}, false);
    						document.getElementById('British Columbia ' + j).addEventListener('mouseout', clearTipIE, false);
    					}			
    					break;	
    				}
    							
    				default:
    				{
    					alert("Error.");	
    				}			
    			}//end switch	
    		}//end root foor loop.
    	});//end document ready statement
    }//end provInfoBox()

    The problem that is occuring, is when a mouse event is fired off it uses the last value for "str", which in the case of this script is always going to contain the data for "British Columbia", as it is the last province defined in the switch statement.

    I would have assumed that whatever the present value of str was at the time the event listener was added would get sent, rather then the present value of str when the method is called.

    Is there an alternative way to do this?

    *I know that using spaces in element ID's is not wise, unfortunately I am not able to change this and I know that this is not the cause of my problem*

  2. #2
    Join Date
    Jul 2011
    Posts
    54
    I think this has to do with the variable being passed to the function ieTip() by it's reference rather then it's value.

    However I have tried using str.value instead of str, but it still doesn't work, it just gives me the contents of str.value as "undefined", even if I have tried defining it by "str.value = ..."

  3. #3
    Join Date
    Apr 2012
    Posts
    55
    You can use a closure to have different values for str for each call. That way, new variables are created for each iteration in the loop, rather than reusing the old ones.

    PHP Code:
    function provInfoBox()
    {                        
        $(
    document).ready(function()
        {            
            for(var 
    2<= 11i++)
            (function() { 
    //[START CLOSURE]
                
    var data provData[i].split(",");
                var 
    provName data[0];
                var 
    provRate data[dateVal];
                var 
    str "Rural " provName ": " provRate '%';

                switch(
    i)
                {
                    case 
    2:
                    {
                        for(var 
    1<= 5j++) 
                        {
                            
    document.getElementById('Newfoundland and Labrador ' j).addEventListener('mouseover', function() {return ieTip(str)}, false );
                            
    document.getElementById('Newfoundland and Labrador ' j).addEventListener('mouseout'clearTipIEfalse );
                        }                            
                        break;    
                    }
                                
                    ...
                                
                    case 
    11:
                    {
                        for(var 
    1<= 6j++)
                        {
                            
    document.getElementById('British Columbia ' j).addEventListener('mouseover', function() {return ieTip(str)}, false);
                            
    document.getElementById('British Columbia ' j).addEventListener('mouseout'clearTipIEfalse);
                        }            
                        break;    
                    }
                                
                    default:
                    {
                        
    alert("Error.");    
                    }            
                }
    //end switch    
            
    })(); //[END CLOSURE]
        
    });//end document ready statement
    }//end provInfoBox() 

  4. #4
    Join Date
    Apr 2012
    Posts
    55
    Here's a simpler example to demonstrate how the above works:

    PHP Code:
    <!doctype html>
    <
    html>
    <
    head><title>example</title>
    <
    script type="text/javascript">
    window.onload = function() {

    var 
    str '';
    for(var 
    010i++) {
        
    str += ',';
        
    setTimeout(function() {
            
    document.body.innerHTML += str '\<br /\>';
        }, 
    100);
    }

    };
    </script>
    </head>
    <body></body>
    </html> 
    You might expect this to output:

    Code:
    0,
    0,1,
    0,1,2,
    0,1,2,3,
    0,1,2,3,4,
    0,1,2,3,4,5,
    0,1,2,3,4,5,6,
    0,1,2,3,4,5,6,7,
    0,1,2,3,4,5,6,7,8,
    0,1,2,3,4,5,6,7,8,9,
    But instead you get:

    Code:
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    0,1,2,3,4,5,6,7,8,9
    However, doing the following fixes the problem:

    PHP Code:
    <script type="text/javascript">
    window.onload = function() {

    var 
    str '';
    for(var 
    010i++)
        (function() { 
    // begin closure
            
    var enclosedStr;
            
    str += ',';
            
    enclosedStr str;
            
    setTimeout(function() {
                
    document.body.innerHTML += enclosedStr '\<br /\>';
            }, 
    100);
        })(); 
    // end closure

    };
    </script> 
    That's because this way a function is called each time the for loop executes, and the function contains a definition for "enclosedStr". That means that variable, rather than being created once (like str), is created 10 times. Therefore, every time the timeout executes, it retrieves its corresponding enclosedStr.

    This technique is called closure, and it is very helpful in JavaScript.

  5. #5
    Join Date
    Jul 2011
    Posts
    54

    Thanks, but that doesn't quite work.

    I am reading up on closures now, I tried to run the code you provided and it doesn't quite work, I am getting an error in firebug "Function requires a name"


    *NVM* I figured it out, was just missing an opening brace on the for loop.

    Thanks .
    Last edited by DaveRich; 04-19-2012 at 02:15 PM. Reason: Figured it out

  6. #6
    Join Date
    Jul 2011
    Posts
    54

    Thought I had it figured out, I was wrong.

    I thought I had the closure thing figured out, however when I tried to implement it in another section of my page I have the same sort of error.

    The output of all of these mouseover functions for the various cities is:
    "undefined: undefined%". This sounds like a closure problem as the arrays containing the data are not defined outside the scope of this function.

    HTML Code:
    function cityTextInfo()
    {
    	$(document).ready(function()
    	{				
    		var cityNames = ["City","St. John's","Halifax","Moncton","Saint John","Saguenay","Québec","Sherbrooke","Trois-Rivières",
    			"Montréal","Gatineau","Ottawa","Kingston","Peterborough","Oshawa","Toronto","Hamilton","St. Catherines-Niagara",
    			"Kitchener-Cambridge-Waterloo","Brantford","Guelph","London","Windsor","Barrie","Greater Sudbury","Thunder Bay",
    			"Winnipeg","Regina","Saskatoon","Calgary","Edmonton","Kelowna","Abbotsford-Mission","Vancouver","Victoria"];
    		var cityRateData = new Array();
    										
    		for(var i = 1; i <= 34; i++)
    		{
    			var curData = cityData[i].split(",");
    			cityRateData[i] = curData[dateVal]; 
    		}
    															
    		for(var i = 1; i <= 34; i++)
    		{
    			(function() //Start of closure
    			{
    					document.getElementById(cityNames[i]).addEventListener('mouseover', function() {return ieTip(cityNames[i] + ": " + cityRateData[i] + '%')}, false);
    					document.getElementById(cityNames[i]).addEventListener('mouseout', clearTipIE, false);
    			})(); //End of closure
    		}
    	});
    }//end cityTextInfo()				

  7. #7
    Join Date
    Apr 2012
    Posts
    55
    The problem here is there are no new variables defined inside the closure.. All are still external to the closure. Try this:

    PHP Code:
            for(var 1<= 34i++)
            {
                (function() 
    //Start of closure
                
    {
                    
    // define some variables within the scope of the closure
                    
    var cityName cityNames[i];
                    var 
    cityRateDatum cityRateData[i];

                    
    document.getElementById(cityName).addEventListener('mouseover', function() {return ieTip(cityName ": " cityRateDatum '%')}, false);
                    
    document.getElementById(cityName).addEventListener('mouseout'clearTipIEfalse);

                })(); 
    //End of closure
            


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