0

I am working with a django 2.0 template, a third party jQuery script for tagging photos, and my "glue" JavaScript code. I am a complete newbie to JavaScript and JQuery.

I can make a successful ajax call to the django template to get the data I want. However, I cannot seem to find a way to make that data available to the rest of my code, and in particular the third party tagging script.

My code:

    (function($) {

    $(document).ready(function(){
        console.log("Made it! Image width="+$( "#img1" ).width()+", height="+$( "#img1" ).height());

        // Ajax request to get the list of auto complete names from the server
        // This function works correctly - all console messages in the function work
        var autoCompleteNames = function() {
            var tmp = null;
            $.ajax({
                url: '/biometric_identification/ajax/get_people_list/',
                type: 'get',
                dataType: 'json',
                success: function (data) {
                    console.log('in success data='+data);
                    tmp = data;
                    console.log('tmp 1='+tmp);
                    console.log('tmp[0]='+tmp[0])
                }
            });
            return tmp;

        }();

        // this statement returns null for autoCompleteNames
        console.log('autoCompleteNames 3='+autoCompleteNames);

        // Stuff for the third party tagging script
        $("#img1").tag({
                showTag: 'always',
                canDelete: true,
                canTag: true,
                defaultTags: [
                {'id':1,'label':'Unchanged','width':283,'height':283,'top':1020,'left':1539},
                {'id':2,'label':'Scaled','width':72,'height':72,'top':208,'left':151},
            ],

            autoComplete: autoCompleteNames,

        });
    });
})(jQuery);

As you can see in the comments in the code, the ajax part works, but when I try to print the list of values to the console outside of the ajax call, the value is null.

How do I get the values from the ajax script into the rest of my code? Is this an issue of scope or a timing issue on when the ajax call returns or something else?

user1045680
  • 815
  • 2
  • 9
  • 19

1 Answers1

0

Since you're using AJAX, the operation happens asynchronously. You need to have your function wait for the variable tmp to be set before continuing forward.

A cheap fix is to put a async: false as a new parameter to the AJAX call, but as said by charlietfl in the comments, this is deprecated and bad practice.

You really should put the rest of your calculations in their own function and call it at the end of the success function in your AJAX call.

  $.ajax({
    url: '/biometric_identification/ajax/get_people_list/',
    type: 'get',
    dataType: 'json',
    success: function(data) {
      $("#img1").tag({
          showTag: 'always',
          canDelete: true,
          canTag: true,
          defaultTags: [{
              'id': 1,
              'label': 'Unchanged',
              'width': 283,
              'height': 283,
              'top': 1020,
              'left': 1539
            },
            {
              'id': 2,
              'label': 'Scaled',
              'width': 72,
              'height': 72,
              'top': 208,
              'left': 151
            },
          ],

          autoComplete: data
      });
    }
  });

Something like the above should do.

el toro
  • 532
  • 4
  • 11
  • Never ever use `async: false`. It is a terrible practice and is deprecated by browser vendors who now log warnings in dev tools console when it is used. – charlietfl Apr 05 '19 at 19:25
  • Since on of my goals is to learn Javascript on this project, what is the preferred (correct?) way to handle this problem? I read in a few posts that this use of async is not desirable. The full project will require several ajax calls to the server for different data values for the $("#img1").tag({}); call to the third party tagging script. – user1045680 Apr 05 '19 at 19:26
  • I'll edit my comment with a more proper answer, as I actually didn't know it was deprecated now. My bad! – el toro Apr 05 '19 at 19:26
  • @user consume the data in the success callback. You can wrap processes that need that data in a function and call the function from `success` and pass the data in if that helps – charlietfl Apr 05 '19 at 19:28
  • I've edited the comment to reorganize your AJAX call. – el toro Apr 05 '19 at 19:33
  • Thanks! It works well. However, I also wanted another ajax call to get the defaultTags from the server. I could pack that data into the autocompleteNames call, but that seems like a poor design from a restful api standpoint. I though an restful api call should focus on a single set of data. Also, I have to do some transformation on the data from the server, so my original design was to (1) get the data from the server, (2) do the calculations, (3) set the values for the #img1 function when the page is done loading. Is that not a good approach? Just trying to learn! – user1045680 Apr 05 '19 at 19:41
  • Well technically, the only way to do that would in fact to have it all be packed inside the success function. That's only *technically* though, as actually you would just write another function that gets called inside the `success` of the first AJAX, and pass the variable from the first AJAX call into it. Then, do the second AJAX call in there. That way you don't have 30 indents in one little function, but still have two AJAX calls that maintain readability. – el toro Apr 05 '19 at 19:49
  • Is that the best design? Or should the data be packed into one ajax call? – user1045680 Apr 05 '19 at 19:53
  • Well I suppose it depends on how much data it is. If it's only a little bit of text like in your post, then sure, pack everything into a single JSON that gets sent from the server. If it's really big though, it might be better to do it asynchronously so the rest of the DOM can load at the same time. – el toro Apr 05 '19 at 19:55
  • It is just 1-10 defaultTags like the fake data in the code. I guess it is easiest to pack the data into one call. I was thinking of putting the transformation calculations for the defaultTags into a separate function to keep the success function a little cleaner. How do I call an external function from the success function and return an object (a list of dictionaries like the defaultTags)? – user1045680 Apr 05 '19 at 20:06
  • Well you might want to start looking into tutorials for basic Javascript for things like calling a function and returning a variable from it. If you've used other programming languages, it's the same idea. In the meantime, don't forget to accept answers if you feel they answered your question :) – el toro Apr 05 '19 at 20:12
  • 1
    Thanks for all your time and help! – user1045680 Apr 05 '19 at 20:30