0

I'm trying to pass local variables to an inline function in javascript and have that (inline) function manipulate those variables, then be able to access the changed variable values in the containing function. Is this even possible? Here's a sample of the code I'm working with:

function addArtists(artist, request, origElm, xml){

//variables
var artistIdArray = [];

/*coding*/

//traverse xml
$('element', xml).each(function(){

/*coding*/ 

$.ajax({  
   /*parameters*/
   success: function(html) {
    var artistAbb = html;

    /*coding*/

    //add this element's id to the array of ids to make it draggable later
    artistIdArray.push(artistAbb);
    alert(artistIdArray[artistIdArray.length - 1]);

 }//end on success    

});//end ajax call

});//end each(function()

 alert(artistIdArray.length);

}

The problem is I keep getting artistIdArray.length = 0, even though elements are several elements are 'alerted' after they're added to the array.

Like I said, I don't know if it's even possible without global variables or objects. Any ideas? Am I totally wrong?

Edit: Entire function

function addArtists(artist, request, origElm, xml){  

//variables  
var artistIdArray = [];

//create ordered list
//set new <ol>s class
var olClass = "artists"; //holds the class of new <ol>

//create id for new <ol>
var olId = "artists"; //holds the id of new <ol>

//create actual <ol> element
var ol = $('<ol></ol>').attr('id',olId)
                      .addClass(olClass)
                      .appendTo(origElm);

//create the <li> elements from the returned xml
//create class for new <li>s, (just the request minus the 's')
var liClass = request.substring(0, request.length-1);
//traverse xml
$('element', xml).each(function(){

    //create id for new <li> based on artist abbreviation
    var artist = $(this).text();        

    $.ajax({
    url: "php/artistToAbb.php", 
        data: {artist: artist}, 
        dataType: "html", 
        async: true,
        success: function(html) {
    var artistAbb = html;

        //create li           
    var li = $('<li></li>').attr('id', artistAbb)
                           .addClass(liClass)
                           .appendTo(ol);   

    //create arrow icon/button for li
    var img = $('<img />').attr('id', artistAbb + 'ArrowImg')
                          .attr("src","images/16-arrow-right.png")
                          .attr('onclick', "expand(this, '" + artistAbb + "', 'years', 'danwoods')")
                          .addClass("expImg")
                          .appendTo(li);    

    var artistTxt = $('<h2>' + artist + '</h2>')
                       .addClass("artist_txt")
                       .attr('onMouseOver', 'catMouseOver(this)')
                       .attr('onMouseOut', 'catMouseOut(this)')
                       .appendTo(li);

    //tag the ol element's class
    $($(origElm)[0]).addClass('expanded');

    //add this element's id to the array of ids to make it draggable later
    artistIdArray.push(artistAbb);
    alert(artistIdArray[artistIdArray.length - 1]);

  }//end on success     

});//end ajax call

});//end each(function()

//make newly added artist elements draggable
for(var n = 0; n < artistIdArray.length; n++){
  //new Draggable(artistIdArray[n], {superghosting: true, detached: true, onEnd: catClearHighlight});
  alert(artistIdArray[n]);
}
alert(artistIdArray.length);  
}
7
  • Alright. With the above code the value of artistNum is incremented within the loop ('call # 1' alerts correct artistNum) but once control moves back too the containing function, the modified value is lost ('call # 2' alerts '0') Commented Dec 23, 2009 at 3:59
  • Try passing it in as an object instead of separate values and they should be handled "by reference" as you're looking for. Commented Dec 23, 2009 at 4:04
  • Here is a blog post about passing values by reference in javascript: snook.ca/archives/javascript/javascript_pass Commented Dec 23, 2009 at 4:05
  • You call #2 references a global artistNum, not the local one defined within addArtists Commented Dec 23, 2009 at 4:05
  • Attempting to achieve the same functionality with .push() Commented Dec 23, 2009 at 4:08

3 Answers 3

4

UPDATED: Now that you've posted your entire code. The answer is that you shouldn't store the elements in the temporary array at all, but create the draggable for each element as the AJAX call returns.

The problem is that while the array is accessible inside the AJAX callback the code at the end of the function (outside the each) executes before the AJAX calls have completed and so the array is empty. If you create each draggable as the call returns, you don't need the intermediate storage variable and the draggable is created as it is inserted into the DOM. The other alternative, would be to make your AJAX calls synchronous {aSync: false}, but this would also potentially tie up the browser until all of the elements have returned. Better, IMO, to live with the asynchronous nature of the AJAX call and handle each element as it is created.

function addArtists(artist, request, origElm, xml){  

    //create ordered list
    //set new <ol>s class
    var olClass = "artists"; //holds the class of new <ol>

    //create id for new <ol>
    var olId = "artists"; //holds the id of new <ol>

    //create actual <ol> element
    var ol = $('<ol></ol>').attr('id',olId)
                          .addClass(olClass)
                          .appendTo(origElm);

    //create the <li> elements from the returned xml
    //create class for new <li>s, (just the request minus the 's')
    var liClass = request.substring(0, request.length-1);
    //traverse xml
    $('element', xml).each(function(){

            //create id for new <li> based on artist abbreviation
            var artist = $(this).text();            

            $.ajax({
        url: "php/artistToAbb.php", 
                data: {artist: artist}, 
                dataType: "html", 
                async: true,
                success: function(html) {
        var artistAbb = html;

                //create li                   
        var li = $('<li></li>').attr('id', artistAbb)
                               .addClass(liClass)
                               .appendTo(ol);   

        //create arrow icon/button for li
        var img = $('<img />').attr('id', artistAbb + 'ArrowImg')
                              .attr("src","images/16-arrow-right.png")
                              .attr('onclick', "expand(this, '" + artistAbb + "', 'years', 'danwoods')")
                              .addClass("expImg")
                              .appendTo(li);    

        var artistTxt = $('<h2>' + artist + '</h2>')
                           .addClass("artist_txt")
                           .attr('onMouseOver', 'catMouseOver(this)')
                           .attr('onMouseOut', 'catMouseOut(this)')
                           .appendTo(li);

        //tag the ol element's class
        $($(origElm)[0]).addClass('expanded');

        new Draggable(artistAbb, {superghosting: true, detached: true, onEnd: catClearHighlight});

      }//end on success     

    });//end ajax call

    });//end each(function()

}
Sign up to request clarification or add additional context in comments.

2 Comments

But would it be possible to access those modified values in the containing function? after the inner function is done executing the outer function still says artistIdArray.length equals 0...
@danwoods: I think the main issue is the asynchronous nature of the Ajax request, when you try to use your array, the Ajax request haven't completed, that's why is empty...
1

You don't need to pass the values at all, just reference them directly in the inline function.

function addArtists(artist, request, origElm, xml){

//variables
var artistIdArray = new Array();
var artistNum = 0;

/*coding*/

//traverse xml  
$('element', xml).each(function(){

                  /*coding*/

    //add this element's id to the array of ids to make it draggable later
    artistIdArray[artistNum] = "some value";
    //alert(artistNum);
    artistNum++;

 }//end on success     

});//end ajax call

});//end each(function()

//test how many elements
 for(var n = 0; n < artistIdArray.length; n++)
   alert(n);

}

2 Comments

I can get the inner function to read the value of the variables just not modify those values (ie: artistNum is always 0)
fixed it part way, see my comment to my own question
1

I can't spot the problem, it probably lies somewhere else than in the as far provided (and edited) code.

But as you're already using jQuery, consider assigning them as "global" jQuery property.

var artistIdArray = [];

would then be

$.artistIdArray = [];

and using it would then look like

$.artistIdArray.push(artistAbb);

you could then at end access it the same way

alert($.artistIdArray.length);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.