0

This is the essence of what I'm trying to do...

Creating a simple page that let's users submit a vacation request. If the request if of type 'Leave of Absence', then a note is required. So, if the request type is 'Leave of Absence', do an Ajax call to the server to get the note count for this request. If it's zero, stop the process. If it's > 0, then save the request.

I'm trying to do this with a promise, but I'm doing something wrong....

for (var i = 0; i < VacationRequests.length; i++)
{
    if (VacationRequests[i].VacationRequestType == leaveOfAbsenceType)
    {
        GetNoteCountPromise.then(function(result) {
            SaveVacationRequest(VacationRequests[i]);
        }, function(err) {
           $('#LeaveOfAbsenceModal').modal('show');
           return;
        });
    }
}

And here's the promise...

    var GetNoteCountPromise = new Promise(function(resolve, reject) {
        $.ajax({
            url: '@Url.Action("GetNoteCount", "VacationRequests")',
            type: 'GET',
            dataType: 'json',
            data: { VacationRequestId: vacationRequestId },
            success: function(data) {
                if (data > 0) {
                    resolve(true);
                }
                else {
                    reject(false);
                }
            }
        });
    });

First question:

I somehow need to pass vacationRequestId into the promise. Not sure how to do that.

Second question:

Am I doing this right?

EDIT:

This what I did first:

for (var i = 0; i < VacationRequests.length; i++)
{
    if (VacationRequests[i].VacationRequestType == leaveOfAbsenceType)
    {
        $.ajax({
            url: '@Url.Action("GetNoteCount", "VacationRequests")',
            type: 'GET',
            dataType: 'json',
            data: { VacationRequestId: vacationRequestId },
            success: function(data) {
                if (data > 0) {
                    SaveVacationRequest(VacationRequests[i]); /// THIS is where it broke down
                }
                else {
                    $('#LeaveOfAbsenceModal').modal('show');
                    return;
                }
            }
        });
    }
}

The problem with this, is that by the time we hit the Success method, the loop had finished and VacationRequests[i] was undefined.

Casey Crookston
  • 13,016
  • 24
  • 107
  • 193

2 Answers2

1

The problem with this, is that by the time we hit the Success method, the loop had finished and VacationRequests[i] was undefined.

In order to solve this issue (refer to closure) you may use an IIFE.

Another solution can be based on javaScript let.

var leaveOfAbsenceType = 1;
var VacationRequests = [{VacationRequestType: 1, VacationRequestId: 1}, {VacationRequestType: 1, VacationRequestId: 2}]
for (var i = 0; i < VacationRequests.length; i++)
{
    if (VacationRequests[i].VacationRequestType == leaveOfAbsenceType)
    {
        (function(i) {
            $.ajax({
                url: 'https://api.github.com/users/octocat/orgs',
                type: 'GET',
                dataType: 'json',
                data: { VacationRequestId: VacationRequests[i].vacationRequestId },
                success: function(data) {
                    console.log('success -->' + i);
                },
                errror: function() {
                    console.log('errror -->' + i);
                }
            });
        })(i);
    }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
gaetanoM
  • 41,594
  • 6
  • 42
  • 61
  • Ok, this seems to be working! Going to test a little more, but so far so good! – Casey Crookston May 23 '17 at 15:16
  • (Not sure who down voted you. I voted it back up. REALLY appreciate the help!) – Casey Crookston May 23 '17 at 15:16
  • Yes, this does look to be working! Thank you! Can I ask you to explain to me what's going on here with the IIFE? Can you explain why this works? – Casey Crookston May 23 '17 at 15:19
  • 2
    @CaseyCrookston the IIFE works because variables in javascript have a function scope. the trailing "(i)" basically says "invoke this function with this argument" and that value for i is then captured and preserved for inside that new function block. – dgeare May 23 '17 at 15:26
1

You're problem is that i is VacationRequests.length (so 1 greater than the highest index) by the time you hear back from the server. It's a frequent issue run into when you're just getting into async programming. To illustrate the problem:

for(var i = 0; i < 5; i++){
  setTimeout(function(){
    console.log(i);
    }, 0);
}

You can fix this by leveraging an IIFE and scoping the variable.

for (var i = 0; i < VacationRequests.length; i++)
{
    function scoping(i){
        if (VacationRequests[i].VacationRequestType == leaveOfAbsenceType)
        {
             var VacationRequestId = i;//or whatever the id is at this location
             GetNoteCountPromise(VacationRequestId).then(function(result) {
                SaveVacationRequest(VacationRequests[i]);
            }, function(err) {
               $('#LeaveOfAbsenceModal').modal('show');
               return;
            });
        }
    }(i)
}

var GetNoteCountPromise = function(vacationRequestId){
return new Promise(function(resolve, reject) {
    $.ajax({
        url: '@Url.Action("GetNoteCount", "VacationRequests")',
        type: 'GET',
        dataType: 'json',
        data: { VacationRequestId: vacationRequestId },
        success: function(data) {
            if (data > 0) {
                resolve(true);
            }
            else {
                reject(false);
            }
        }
    });
});
};

Also we can get the vacationRequestId into a closure to make it accessible to the promise.

dgeare
  • 2,618
  • 5
  • 18
  • 28