0

I'm new to working with AJAX, but I've been researching it for the past two hours to help in my scenario. I haven't made any progress. :(

Regardless, my issue is that the subPages array is out of scope when I'm outside $.get(...). I've tried using when() and done() for my code, but just can't get it right still.

I think the problem lies within the iterations going through a for loop since I have pages[i] in multiple sections of my code being used. That's why I can't use when() and done() when needed.

Here's what I have:

var subPages = [];
var containsSub = '/sites/Pages/';
var tempString = '';

// iterate through the pages array in reverse
for(var i = pages.length - 1; i >= 0; i--){
    // grab all <a> within response text
    var getLinks = $.get(baseURL + pages[i]).then(function(responseData){
        var $response = $(responseData);
        var $links = $response.find('a');
        // push each valid link into subPages array
        $links.each(function(index, $link){
            if(this.href.indexOf(containsSub) > -1){
                subPages.push(this.href);
            }
        });
        // subPages array is loaded with the correct values
        console.log("subPages inside get: " + subPages);
    });

    // empty here
    console.log("subPages outstide all: " + subPages);

Edit: With the addition of the then chain and code, I'm having an undefined for subPages[i]

var subPages = [];
        var containsSub = '/sites/Pages/';
        var tempString = '';

        // iterate through the pages array in reverse
        for(var i = pages.length - 1; i >= 0; i--){
            // grab all <a> within response text
            var getLinks = $.get(baseURL + pages[i]).then(function(responseData){
                var $response = $(responseData);
                var $links = $response.find('a');
                // push each valid link into subPages array
                $links.each(function(index, $link){
                    if(this.href.indexOf(containsSub) > -1){
                        subPages.push(this.href);
                        //console.log("<a href='"+ this.href + "'>" + this.href + "</a>" + " <br>");
                    }
                });
            console.log("subPages inside get: " + subPages);
            })
            .then(function(){
                console.log("subPages outstide all: " + subPages);

            // print bold for current main page
            tempString += "<strong><a href='"+ baseURL + pages[i] + "'>" + pages[i].substr(27,pages[i].length) + "</a><strong>" + " <br>";

            for(var i = 0; i < subPages.length - 1; i++){
                console.log("<a href='"+ subPages[i] + "'>" + subPages[i] + "</a>" + " <br>");
            }

            subPages = [];

            pages.splice(i, 1);
            })


        }

11/25 Edit: I fixed the issue below with my answer by removing some complications and decided that an AJAX request was more in logic.

var subPages = [];
    var containsSub = '/sites/it/InfoProtect/Pages/';
    var tempString = '';

    // iterate through the pages array in reverse
    for(var i = pages.length - 1; i >= 0; i--){
        // grab all <a> within response text
        var getLinks = $.ajax({
            url: baseURL + pages[i], 
            async: false,
            success: function(responseData){
                var $response = $(responseData);
                var $links = $response.find('a');
                // push each valid link into subPages array
                $links.each(function(index, $link){
                    if(this.href.indexOf(containsSub) > -1){
                        subPages.push(this.href);
                    }
                });
            }
        })
Andy
  • 51
  • 1
  • 9
  • 1
    Where is `subPages` defined? – Merott Nov 24 '15 at 16:07
  • @Merott It's defined before the for loop. I forgot to paste that, so I added it in. – Andy Nov 24 '15 at 16:09
  • 2
    You can't use the result of the AJAX request *outside* the callback. –  Nov 24 '15 at 16:09
  • @squint Is there a way I could? – Andy Nov 24 '15 at 16:10
  • 1
    @Andy: No. This task will be simpler if you can turn this into a single request. Better to avoid sending off multiple requests at once. But ultimately when the request (or requests) are done, you need to pick up the flow from inside the callback. –  Nov 24 '15 at 16:11

3 Answers3

1

Your for loop immediately executes all iterations of the loop. The subPages array is populated after the last line of console.log has run.

Merott
  • 7,189
  • 6
  • 40
  • 52
0

issue is that the subPages array is out of scope when I'm outside $.get(...)

$.get() returns an asynchronous response . Try chaining .then() to $.get() to maintain same scope as initial .then()

var getLinks = $.get(baseURL + pages[i]).then(function(responseData){

})
.then(function() {
  console.log("subPages outstide all: " + subPages);
})

Try creating an IIFE within for loop to pass i

e.g.,

var pages = ["a", "b", "c"];

for(var i = pages.length -1; i >= 0; i--) {
  (function(j) {
  var dfd = $.Deferred(function(d) {
    setTimeout(function() {
      d.resolve(j)
    }, Math.random() * 1000)
  }).promise()
  .then(function(n) {
    console.log("first", n, pages[n]);
    return n
  }).then(function(res) {
    console.log("second", res, pages[res])
  })
  }(i))
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
guest271314
  • 1
  • 15
  • 104
  • 177
  • @squint _"It is chained... – "_ Where ? – guest271314 Nov 24 '15 at 16:13
  • `$.get(baseURL + pages[i]).then(function(responseData){` –  Nov 24 '15 at 16:13
  • @squint Note that last `console.log()` is outside of `.then()` at OP where comment `// empty here` is – guest271314 Nov 24 '15 at 16:14
  • Yes, your update makes more clear what you meant. –  Nov 24 '15 at 16:15
  • Curious, how is that different from just putting the `console.log()` in the first `then`. I haven't used deferreds. –  Nov 24 '15 at 16:16
  • @squint No different at example at OP . The solution is to place `js` that uses response from `$.get()` in initial `.then()`. Would perhaps be difference if initial `.then()` performs action that would return different result to chained `.then()` . Not appear to be deferred at Question, but jQuery promise object. – guest271314 Nov 24 '15 at 16:20
  • @guest271314 Thanks for the response. The data is sent, but I'm having an issue with `Uncaught TypeError: Cannot read property 'substr' of undefined` when I add in the rest of my code within the then portion. – Andy Nov 24 '15 at 16:24
  • @Andy Try returning `i` from first `.then()` to second `.then()` – guest271314 Nov 24 '15 at 16:32
  • @Andy Try creating an IIFE where `i` is passed https://jsfiddle.net/05fssusa/1/ – guest271314 Nov 24 '15 at 16:47
  • @guest271314 Still same error, undefined. I didn't see the previous comment. Let me try that. – Andy Nov 24 '15 at 16:49
  • @Andy See stacksnippets at updated post ; note `i` may not be in order in `.then()` due to asynchronous `$.get()` . If order is a requirement , try substituting `.queue()` for `for` loop to call next `$.get()` when previous `$.get()` has completed – guest271314 Nov 24 '15 at 16:55
0

$.get is asynchronous, so after calling it, the code inside .then is not immediately called. So, it continues to the next iteration of your loop, finally exits, and shows an empty subpages array, because your data hasn't returned yet.

Here's a quick idea of how to wait for your ajax calls, prior to logging the array (untested):

var ajaxCalls = [];
// iterate through the pages array in reverse
for(var i = pages.length - 1; i >= 0; i--){
    // grab all <a> within response text
    var getLinks = $.get(baseURL + pages[i]).then(function(responseData){
        var $response = $(responseData);
        var $links = $response.find('a');
        // push each valid link into subPages array
        $links.each(function(index, $link){
            if(this.href.indexOf(containsSub) > -1){
                subPages.push(this.href);
            }
        });
        // subPages array is loaded with the correct values
        console.log("subPages inside get: " + subPages);
    });
    ajaxCalls.push(getLinks);
}

$.when.apply(null, ajaxCalls).then(function() {
    // not empty here
    console.log("subPages outstide all: " + subPages);
});
TbWill4321
  • 8,626
  • 3
  • 27
  • 25
  • Does this maintain the order of the requests? Since he's sending them last to first, it seems like there's a specific order to be maintained. –  Nov 24 '15 at 16:18
  • No, but that wasn't included as a requirement. – TbWill4321 Nov 24 '15 at 16:20
  • You're right that it wasn't an explicit requirement but I think it's a pretty safe bet given the reverse iteration of the loop. Ultimately the OP would have to answer that. –  Nov 24 '15 at 18:46