Search code examples
javascriptjquerylistgetjson

Why my JavaScript function is executing uncertainly if i add an alert()?


I wrote the function below to get the length of a listbox with the id courselessons. The problem is that when I comment the alert() the function changecheckbox works only once.

If I remove the alert it works fine. But I don't want to have an alert on every single click.

The selOpts shows correct content only for the first time.

JavaScript:

function changecheckbox() {
   //alert("function called...");
   var selOpts = document.getElementById("courselessons").length();
   alert(selOpts);
   if (selOpts > 0) {
       $('#taskassignment').prop('disabled', false);
   }
   else {
       $('#taskassignment').prop('disabled', true).prop("checked", false);
   }
}

function addItem() {
   if (seltask == undefined || seltask.length === 0) {
       return;
   }
   var lessonsDropdown = $('#courselessons');
   lessonsDropdown.empty();
   $("#tasks option:selected").appendTo("#coursetasks");
   $("#coursetasks option").attr("selected", false);
   if (seltask.length > 0) {
       cacheToken = new Date().getTime();
       // retrieve data using a Url.Action() to construct url
       $.getJSON('@Url.Action("AddTaskToCourse")', {
           task: seltask,
           lesson: lesson,
           _: cacheToken
       });
       $.getJSON('@Url.Action("UpdateLessonInCourse")', {
           _: cacheToken
       }).done(function (data) {
           //re-enable tasks drop down
           //for each returned tasks
           $.each(data, function (i, lessons) {
               //Create new option
               var test = $('<option />').html(lessons);
               //append tasks taskss drop down
               lessonsDropdown.append(test);
           });
           seltask = null;
       });
    }
    changecheckbox();
}

HTML:

<button type="button" id="btnAdd" onclick="addItem(); changecheckbox();">Add Item</button>

Solution

  • The code inside addItem() is making a GET request to a resource asynchronously. This means the code which comes after this function to be execute will not wait for its execution to get complete.

    When I uncomment the alert it works fine.

    That is because as the alert() is built in, it halts the execution of script until user interaction. This gave the time addItem() needs and everything seems to work.

    Fortunately, there are solutions available to handle this situation.

    1. Promise.
    2. Rearrange your code to work with callbacks.

    Under the covers, $.getJSON is shorthand for making a GET request using ajax with datatype = 'json'and it returns a promise object which basically tells that please wait honey, i will give you something which could be a success or a failure but sometime later.

    So yes, you can easily call the function inside the done().

    NOTE: These things have been explained pretty well on web so i will not reinvent the wheel :)

    Keeping the things simple...

    function addItem() {
    
        // Rest of the code...
    
        if (seltask.length > 0) {
            cacheToken = new Date().getTime();
            // retrieve data using a Url.Action() to construct url
            $.getJSON('@Url.Action("AddTaskToCourse")', {
                task: seltask,
                lesson: lesson,
                _: cacheToken
            });
            $.getJSON('@Url.Action("UpdateLessonInCourse")', {
                _: cacheToken
            }).done(function (data) {
                //re-enable tasks drop down
                //for each returned tasks
                $.each(data, function (i, lessons) {
                    //Create new option
                    var test = $('<option />').html(lessons);
                    //append tasks taskss drop down
                    lessonsDropdown.append(test);
                });
                seltask = null;
                changecheckbox();
            });
    
        }        
    }
    

    After this setup, you should remove the changecheckbox() call from the button onclick otherwise it would make it execute twice.