简体   繁体   中英

jQuery : How can I call $.ajax when a particular condition is met in the nested ajax calls scenario?

Updated Question with Code

I have a situation where I am calling two nested ajax calls one after another. The first ajax call submits a form without the attachment. The result of the first ajax call will create a requestId and using second ajax call I have to attach multiple attachments to the created requestId .

The result of below code, both first and second ajax calls are being called N times of attachment. For ex:- If there are 3 attachments, createRequestId ajax call(first ajax call) called 3 times which creates 3 requestId s. My issue is, createRequestId ajax call needs to be called only one time (first time) and during rest of the loop, only the second ajax call should be called. How can I achieve this in the below code?

Current situation

RequestId 1,Attachment 1
RequestId 2,Attachment 2
RequestId 3, Attachment 3

Expected output

RequestId 1, Attachment 1, Attachment 2, Attachment 3

//loop through number of attachments in the form
$("#myDiv").find("input[type=file]").each(function(index,obj) {
   var fObj = $(obj),
       fName = fObj.attr("name"),
       fileDetail = document.getElementById(fName).files[0];
       //FileSize Validation
       if(fileDetail !=undefined && fileDetail !=null)
        {
          if(fileDetail.size > 5*Math.pow(1024,2))

           { 
              alert("Please upload the attachment which is less than 5 MB");
              return false
           }
         }

       $.ajax({    //First Ajax Call
          url: 'http://..../createRequestId'
          type:'POST'
          data: stringify(formData)
          success: function(resObj){
             $("#showResponseArea span").removeClass("hide");
             $("#showResponseArea span").removeClass("alert-success");
             var requestId = resObj.requestId;    

              if(requestId>1 && fileDetail !=undefined && fileDetail !=null) {
                 $.ajax({       //Second Ajax Call
                     url: 'http://..../doAttach?fileName=' + fileDetail.name + 
                           '&requestId=' +requestId,    
                     type:'POST',
                     data: fileDetail,
                     success: function(resObj){
                               alert("Attachment Successful");

                      }
                      error : function(data) {
                        alert("Failed with the attachment");
                       }
                  });                
                } 
               },
              error: funciton(resObj) {
                    alert("Some Error Occured");
              }
           });
        });

I know this doesn't really answer your question in full, but if you don't mind me offering a little constructive code review. It's hard to really manage and debug code when it's all thrown into one big function with many lines, especially if you're nesting async calls (you're getting close to nested callback hell). There's a reason code like this can get hard to maintain and confusing.

Lets incorporate some Clean Code concepts which is to break these out into smaller named functions for readability, testability, and maintainability (and able to debug better):

First you don't need all those !== and undefined checks. Just do:

if (fileDetail)

and

if(requestId>1 && fileDetail)

that checks for both null and undefined on fileDetail.

Then I'd start to break out those two ajax calls into several named functions and let the function names and their signatures imply what they actually do, then you can remove unnecessary comments in code as well as once you break them out, typically you can find repeated code that can be removed (such as redundant post() code), and you will find that code you extracted out can be tested now.

I tend to look for behavior in my code that I can try to extract out first. So each one of those ​if​ statements could easily be extracted out to their own named function because any if statement in code usually translates to "behavior". And as you know, behavior can be isolated into their own modules, methods, classes, whatever...

so for example that first if statement you had could be extracted to its own function. Notice I got rid of an extra if statement here too:

function validateFileSize(fileDetail)
    if(!fileDetail && !fileDetail.size > 5*Math.pow(1024,2)){
      alert("Please upload the attachment which is less than 5 MB");
      return false
    };
};

So here's how you could possibly start to break things out a little cleaner (this could probably be improved even more but here is at least a start):

$("#myDiv").find("input[type=file]").each(function(index,obj) {
    var fObj = $(obj),
        fileName = fObj.attr("name"),
        file = document.getElementById(fileName).files[0];

    validateFileSize(file);
    post(file, 'http://..../createRequestId');
});

// guess what, if I wanted, I could slap on a test for this behavior now that it's been extracted out to it's own function
function validateFileSize(file){
    if(!file && !file.size > 5*Math.pow(1024,2)){
        alert("Please upload the attachment which is less than 5 MB");
        return false
    };
};

function post(url, data){
    $.ajax({
        url: url,
        type:'POST',
        data: stringify(data),
        success: function(res){
            showSuccess();

            var id = res.requestId;

            if(id > 1 && file){
                var url = 'http://..../doAttach?fileName=' + file.name + '&requestId=' + id;
                postData(file, url);
            }
        },
        error: function(err) {
            alert("Some Error Occurred: " + err);
        }
});

// I didn't finish this, and am repeating some stuff here so you could really refactor and create just one post() method and rid some of this duplication
function postData(file, url){
    $.ajax({
        url: url,
        type:'POST',
        data: file,
        success: function(res){
            alert("Attachment Successful");
        },
        error : function(data) {
            alert("Failed with the attachment");
        }
    });
};

// this is behavior specific to your form, break stuff like this out into their own functions...
function showSuccess() {
    $("#showResponseArea span").removeClass("hide");
    $("#showResponseArea span").removeClass("alert-success");
};

I'll leave it here, next you could get rid of some of the duplicate $ajax() code and create a generic post() util method that could be reused and move any other behavior out of those methods and into their own so that you can re-use some of the jQuery ajax call syntax.

Then eventually try to incorporate promises or promises + generators chain those async calls which might make it a little easier to maintain and debug. :).

I think your loop is simply in the wrong place. As it is, you're iterating files and making both AJAX calls once. Edit : I now show the appropriate place to do extra validations before the first AJAX call. The actual validation was not part of the question and is not included, but you can refer to JavaScript file upload size validation .

var fileSizesValid = true;
$("#myDiv").find("input[type=file]").each(function(index, obj) {
  // First loop checks file size, and if any file is > 5MB, set fileSizesValid to false
});

if (fileSizesValid) {
  $.ajax({ //First Ajax Call
    url: 'http://..../createRequestId',
    type: 'POST',
    data: stringify(formData),
    success: function(resObj) {
      var fObj = $(obj),
        fName = fObj.attr("name"),
        fileDetail = document.getElementById(fName).files[0];
      //loop through number of attachments in the form
      $("#myDiv").find("input[type=file]").each(function(index, obj) {

        $("#showResponseArea span").removeClass("hide");
        $("#showResponseArea span").removeClass("alert-success");
        var requestId = resObj.requestId;

        if (requestId > 1 && fileDetail != undefined && fileDetail != null) {
          $.ajax({ //Second Ajax Call
            url: 'http://..../doAttach?fileName=' + fileDetail.name +
              '&requestId=' + requestId,
            type: 'POST',
            data: fileDetail,
            success: function(resObj) {
              alert("Attachment Successful");
            },
            error: function(data) {
              alert("Failed with the attachment");
            }
          });
        }
      })
    },
    error: function(resObj) {
      alert("Some Error Occured");
    }
  });
}

As a side note, take care where you place your braces. In JavaScript your braces should always be at the end of the line, not the start. This is not a style preference thing as it is most languages, but an actual requirement thanks to semicolon insertion .

Try following code (Just a re-arrangement of your code and nothing new):

//loop through number of attachments in the form
var requestId;
$("#myDiv").find("input[type=file]").each(function(index,obj) {
   var fObj = $(obj),
   fName = fObj.attr("name"),
   fileDetail = document.getElementById(fName).files[0];
   //FileSize Validation
   if(fileDetail !=undefined && fileDetail !=null)
    {
      if(fileDetail.size > 5*Math.pow(1024,2))

       { 
          alert("Please upload the attachment which is less than 5 MB");
          return false
       } else if(!requestId || requestId <= 1){
          $.ajax({    //First Ajax Call
          url: 'http://..../createRequestId'
          type:'POST'
          data: stringify(formData)
            success: function(resObj){
                $("#showResponseArea span").removeClass("hide");
                $("#showResponseArea span").removeClass("alert-success");
                requestId = resObj.requestId;  
                    secondAjaxCall(fileDetail);
            },
            error: funciton(resObj) {
                alert("Some Error Occured");
            }
          });
       } else if(requestId>1) {
            secondAjaxCall(fileDetail);        
        }

     }


    });

    function secondAjaxCall(fileDetail) {
        $.ajax({       //Second Ajax Call
             url: 'http://..../doAttach?fileName=' + fileDetail.name + 
                   '&requestId=' +requestId,    
             type:'POST',
             data: fileDetail,
             success: function(resObj){
                       alert("Attachment Successful");

              }
              error : function(data) {
                alert("Failed with the attachment");
               }
          });     
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM