Undefined message tacked onto the start of a string

Hi.

I am trying to loop through a json result to create a table which I can do fine. The problem I am having is that at the start of the string I have the ‘undefined’ tacked to the start of it and I cant see where it is coming from.

this is my code.

my json result set is: {“errorIsSet”:“1”,“results”:[“The title must not be empty”,“Cost is not correct”]}


var obj = jQuery.parseJSON(data);
if(obj.errorIsSet==1)
{
var i;
var errorImage = '<img src="images/warning.gif" alt="Warning!" width="24" height="24" style="float:left; margin: -5px 10px 0px 0px; " />';
var tableMiddle;
var tableTop = '<table width="100%" border="0" cellspacing="0" cellpadding="0">' ;
for(var i in obj.results)
{
tableMiddle +=  '<tr><td>'+errorImage+'</td><td>'+obj.results[i]+'</td></tr>';
alert (tableMiddle);
}
var tableBottom = '</table>';
var errorTable = tableTop+tableMiddle+tableBottom;
alert (errorTable);
$("div.error").empty(this).append(errorTable);
$("div.error").show();
}  

And this is the resultant html


<table width="100%" border="0" cellspacing="0" cellpadding="0">
undefined<tr><td><img src="images/warning.gif" alt="Warning!" width="24" height="24" style="float:left; margin: -5px 10px 0px 0px; " /></td>
<td>The title must not be empty</td></tr>
<tr><td><img src="images/warning.gif" alt="Warning!" width="24" height="24" style="float:left; margin: -5px 10px 0px 0px; " /></td>
<td>Cost is not correct</td></tr></table>

Thanks for your help.
Chris

Hi Chris,

The issue is that tableMiddle gets declared, but no default value gets assigned to it. Then when you try to add a string to this value, its “value” gets stringified. Of course, right at the start, it isn’t defined (i.e. undefined). Hence you end up with “undefined <tr><td …”

I’ve had quick look at your code and added some comments and small modifications.


/*
  Declare all your variables in one place near the top of your current scope.
  This will help you keep track of them a lot easier.
  JavaScript uses something called "variable hoisting", which effectively
  means that any vars you declare in your code, get hoisted up and declared
  at the "top" of the current scope.
  See [3], [4] and [5] for info about scope
*/
var i = 0,
    obj = {},
    resultsLength = 0,
    errorImage = "",
    tableMiddle = "", //the fix for this code was to instantiate tableMiddle as a String
    tableTop = "",
    errorTable = "";

/* 
  Note that the above is just a short way to define multiple variables, 
  you could also do it like this:
  var a, b, c, d;
 
  or like this:

  var a;
  var b;
  var c;
*/
obj = jQuery.parseJSON(data);


if( obj.errorIsSet == 1 ) {

    errorImage = '<img src="images/warning.gif" alt="Warning!" width="24" height="24" style="float:left; margin: -5px 10px 0px 0px; " />';

    tableTop = '<table width="100%" border="0" cellspacing="0" cellpadding="0">';

    //getting the length of the results array and caching it
    resultsLength = obj.results.length;

    //using a regular for loop to iterate over an array
    for( i = 0; i < resultsLength; i++ ) {

        tableMiddle +=  '<tr><td>'+errorImage+'</td><td>'+obj.results[i]+'</td></tr>';

        /*
          I've replaced alerts with console.log() as it doesn't interfere with the flow
          of the program (and saves you having to click the dialog boxes ever time).
          See Links [1] and [2]
        */
        console.log( tableMiddle );
    }

    tableBottom = '</table>';
    errorTable = tableTop+tableMiddle+tableBottom;

    console.log( errorTable );

    $("div.error").empty(this).append(errorTable);
    $("div.error").show();
}
 

Links:
[1] http://code.google.com/chrome/devtools/docs/console.html
[2] http://getfirebug.com/logging
[3] http://coding.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/
[4] http://snipt.net/geekyjohn/javascript-localglobal-scope-example
[5] https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope

Hi.

Thanks so much for taking the time to answer this so carefully. I appreciate it.

Chris