0

I am familiar with the nuances of async javascript calls. All work with data returned from an async call must be done in the callback. Roger that.

In the following code, my .ajax() call retrieves a serialised list of crew members from a C# generic handler, and the callback contains a .get() (which is also async), that retrieves a template and merges each crew member's data with the html template, and injects it into the page.

All that works fine, however, at the end, every iteration through the loop finishes and every panel inserted on the page contains only data from the last crew member in the list.

So, I end up with ALL panels on the page being for the same person. The last person in the list.

The .get() is being issued from within the callback of the .ajax(). The work is being performed in the .done() callback of the inner .get().

This should be safe, I thought. The work is being done in the callback of the .ajax() call, and the work with that data is being performed in the .done() callback of the .get().

What happens is that the loop fires all "1 to n" times. And THEN the .done() call back fires "1 to n" times.

I suspect that even though the .get() is called inside a for loop, the for loop is not async, and there's a problem in that somewhere.

$.ajax({

    type: "POST",
    url: "js/handlers/LoadCrew.ashx",
    dataType: "text",
    cache: false,

    success: function (ajaxResult) {

        var crew = JSON.parse(ajaxResult);

        for (var i = 0; i < crew.length; i++) {

            var thisCrewMember = crew[i];
debugger;

            var getScript = $.get({
                url: "templates/CrewPanel.html",
                dataType: "text",
                data: thisCrewMember
            })

            .done(function (template) {
debugger;
                template = template.replace("[[NAME]]", thisCrewMember.NAME);
                document.getElementById("CrewPanels").innerHTML += template;
            })

            .fail(function () {
                alert("Failed to retrieve template: CrewPanel.html");
            })
        }
    },

    error: function (result) {
        return false;
    }

});

Can someone tell me if what I am trying to do is even possible, and if so, how?

Edit

Added the two debugger statements to the code listing.

I'm not sure this is a scoping issue. At execution time, in the Chrome debugger, (assume 8 rows of JSON data from the generic handler), it will break 8 times on the first debugger statement, THEN it will break 8 times on the second debugger statement in the done() callback.

When it does this, of course, the for loop has finished it's iterations and thisCrewMember is sitting on the last value assigned.

Thanks for the comments, but I think this is an async issue, even though I'm doing the work in the callback functions. If not, can someone explain how scoping is the issue?

Edit 2

I take it back. Changing var to const as PaulPro suggested does indeed fix things. I guess I do not understand how thisCrewMember is scoped. But the suggested change has resulted in better results.

halfer
  • 19,824
  • 17
  • 99
  • 186
KWallace
  • 1,570
  • 1
  • 15
  • 25
  • Have you tried to substitute the for loop with `forEach`? – Anton Harniakou May 14 '18 at 17:31
  • 1
    Because `var` is function scoped and not block scoped, you only have one `thisCrewMember`. Replacing `var` with `const` would fix it, but that only works in modern browsers or with a transpiler (babel). There are many other fixes in the question I linked (as @tryzniak mentioned, using forEach instead of a for loop is one option). – Paul May 14 '18 at 17:32
  • Thanks, Paulpro! Will check – KWallace May 14 '18 at 17:45
  • Hmmmn. Moving "var thisCrewMember" outside the loop (to the first line inside the "success(): " function didn't change anything. The only thing I can think of is to move it completely outside of the ajax call altogether. Is that what you are proposing? – KWallace May 14 '18 at 18:55
  • And, out of curiosity, how would using forEach() be any different than a for loop where scope is concerned? – KWallace May 14 '18 at 18:56
  • @KirbyL.Wallace Please use `@Paulpro` if you comment to me so I get notified. I only just now saw your comments because you edited the question and it appeared on the recently active questions list again. – Paul May 14 '18 at 19:26
  • @KirbyL.Wallace Moving it outside the loop doesn't change anything because `var` uses function scope not block scope. Switching to `const` or `let` (***and*** keeping it inside the loop!) would work because those are block scoped, so each iteration of the loop gets its own copy of the variable. – Paul May 14 '18 at 19:27
  • @KirbyL.Wallace `forEach` takes a function as a callback, so it basically makes the fact that `var` is function scoped not matter because each iteration gets its own function anyway. That means `var` inside a forEach callback is similar to `let` inside a regular loop: each iteration gets its own copy of the variable. – Paul May 14 '18 at 19:28
  • @Paulpro - If you will add this as an answer, I will gladly give you the vote. And thanks for the forEach clarification. That will help because I have similar issues that I edited out of the question for brevity, and to focus on the problem. Your input will solve those issues also! Thanks!. ;-) ALSO..... Thank you for being patient with me doubting your answer. ;-) – KWallace May 14 '18 at 19:30
  • @Paulpro - SO is starting to warn me about starting a conversation. Is there some way I can "like" or "follow" you so I can keep in touch with other answers you provide? I can't find any "message me" option on your profile. LinkedIn, maybe? – KWallace May 14 '18 at 19:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/171029/discussion-between-kirby-l-wallace-and-paulpro). – KWallace May 14 '18 at 19:44

0 Answers0