0

Good day,

I have the List. The List has checkbox field "DocOrg". The user must select checkbox "DocOrg" value and the script must send ajax query to another list, find another list element by "DocOrg" value and get its field "OrgIndex" value. Then "OrgIndex" value I must add to document "Title" field value. The ajax request works fine. But I can't get return value from getDocOrganization() function. The var orgIndex is equal "". I try to change form Title field value inside the getDocOrganization() function, but this change doesn't save after document saving. How can I get "OrgIndex" value by ajax request, add it to document "Title" field and save this field value in document? When I use "alert" it works fine, but if I don't use alert, it doesn't work.

My script


<script type="text/javascript" src="/SiteAssets/Script/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="/SiteAssets/Script/jquery.SPServices.min.js"></script> 

<script type="text/javascript">

var checkedAttr = [];
var autoDocNum="";

    $(document).ready(function () {



        $("input:checkbox[id^='DocOrg']").change(function () {
            checkedAttr=[];
                $("input:checkbox[id^='DocOrg']:checked").each(function(){
                    checkedAttr.push($(this).next().text());
                });
        });     



    });

    function PreSaveItem(){
  var err = false;
  var docType="";
        if (checkedAttr.length>1) {
            autoDocNum=$("input[id^='Title']").val() + " " + "is";
        }
        else if (checkedAttr.length==1) {
            
            autoDocNum=getDocOrganization();
            setTimeout(1000);
        //  alert(autoDocNum);
            //$("input[id^='Title']").val(autoDocNum);
        }   
  return !(err)
}

function getDocOrganization(){
    
    var docOrg = checkedAttr[0];    //get the label for this checkbox
   // alert("checked  : " + docOrg);
    var orgIndex="";
//  alert('docTitle ' +$("input[id^='Title']").val());
    
    var url = '/ISM';

       $.ajax({ 
        url: url + "/_api/web/lists('1E685303-0E60-435B-A8EE-EBB834165C06')/items?$filter=Title eq '" + encodeURIComponent(docOrg) + "'",
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: function (data) {

           if (data.d.results.length!=0){
                orgIndex = data.d.results[0].OrgIndex;  
                
                $("input[id^='Title']").val($("input[id^='Title']").val() + " " + orgIndex);
                //alert($("input[id^='Title']").val());
                
            }
        },
        error: function (error) {
             console.log(JSON.stringify(error));
            
        }
    });
    
    //alert ('orgIndex ' +orgIndex);
     console.log('orgIndex = ' +orgIndex);
    return orgIndex.toString();
}

</script>

1 Answer 1

0

This is happening because you aren't anticipating the fact that AJAX calls are asynchronous, which makes it a little more complicated to understand the order in which your code executes.

Simply put, because the AJAX call is asynchronous, the code inside the success function executes after you try to return a value from your getDocOrganization function.

To see this in action, try adding the following console.log() entries (also, as a side note, you should really be using PreSaveAction instead of PreSaveItem):

function PreSaveAction() {

    var autoDocNum = getDocOrganization();
    console.log('value returned from getDocOrganization:', autoDocNum);

    // just return false to prevent saving, just for this test
    return false;
}

function getDocOrganization() {

    var docOrg = checkedAttr[0];
    var orgIndex = "";
    var url = '/ISM';

    console.log('starting ajax call now.');
    $.ajax({
        url: url + "/_api/web/lists('1E685303-0E60-435B-A8EE-EBB834165C06')/items?$filter=Title eq '" + encodeURIComponent(docOrg) + "'",
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: function (data) {

            console.log('ajax call complete - success');
            if (data.d.results.length != 0) {
                orgIndex = data.d.results[0].OrgIndex;
                $("input[id^='Title']").val($("input[id^='Title']").val() + " " + orgIndex);
            }
        },
        error: function (error) {
            console.log('ajax call complete - error');
            console.log(JSON.stringify(error));
        }
    });

    console.log('getDocOrganization function complete, returning orgIndex:', orgIndex);
    return orgIndex.toString();
}

You will see the following in the console:

starting ajax call now.
getDocOrganization function complete, returning orgIndex:
value returned from getDocOrganization:
ajax call complete - success

So, not only do you have to anticipate the asynchronous nature of the AJAX call, but you have the added complication that PreSaveAction does not handle async execution very well.

I have dealt with this kind of situation before, and to get it to work, you will need to use a variable as a flag in order to control how PreSaveAction works, and you will actually have to re-trigger it from code after you get the value you want from your AJAX call.

<script type="text/javascript">
var checkedAttr = [];

// we don't need this since we will set the Title field directly
// var autoDocNum = "";

// this is the flag we will use to make sure
// PreSaveAction waits for the async call
var receivedOrgIndex = false;

$(document).ready(function () {
    $("input:checkbox[id^='DocOrg']").change(function () {
        checkedAttr = [];
        $("input:checkbox[id^='DocOrg']:checked").each(function () {
            checkedAttr.push($(this).next().text());
        });
    });
});

function PreSaveAction() {

    // check the flag to see if we have made the ajax call yet
    if (!receivedOrgIndex) {

        // STEP 1

        // if we have not:
        
        // for extra safety, in case the ajax call takes longer than expected,
        // disable the Save button so users don't click it twice
        $('input[type="button"][value="Save"]').prop('disabled', true);

        // start the async call
        getDocOrganization();

        // return false from PreSaveAction to prevent the form from saving
        // until we have the data from the ajax call
        return false;

    } else {

        // STEP 4

        // the flag is set to true, so we must have our result
        // from the ajax call now, and we set the Title field
        // in the success function, so just return true from PreSaveAction
        // now that the form is filled out correctly and we are ready to save
        return true;
    }
}

function getDocOrganization() {

    // STEP 2

    var docOrg = checkedAttr[0];    //get the label for this checkbox
    var url = '/ISM';

    $.ajax({
        url: url + "/_api/web/lists('1E685303-0E60-435B-A8EE-EBB834165C06')/items?$filter=Title eq '" + encodeURIComponent(docOrg) + "'",
        method: "GET",
        headers: { "Accept": "application/json; odata=verbose" },
        success: function (data) {

            // STEP 3

            // no matter what, re-enable the Save button
            $('input[type="button"][value="Save"]').prop('disabled', false);

            if (data.d.results.length != 0) {

                // we got results, so set our flag
                receivedOrgIndex = true;

                orgIndex = data.d.results[0].OrgIndex;

                // set the title field value
                $("input[id^='Title']").val($("input[id^='Title']").val() + " " + orgIndex);

                // now the tricky part - since we now have the value we wanted
                // from the async call, and we set our flag to let PreSaveAction
                // know that we got it, we need to "click" the Save button
                // again to re-trigger the PreSaveAction and allow the form to save
                $('input[type="button"][value="Save"]').click();
            }
        },
        error: function (error) {
            // no matter what, re-enable the Save button
            $('input[type="button"][value="Save"]').prop('disabled', false);

            console.log(JSON.stringify(error));
        }
    });
    // no need to actually return anything from this function
    // since we are setting the Title field in the success function
}

</script>

Now, I saw in your original code sample, you are doing something different if more than one checkbox is checked, and this example does not look at that or deal with that at all, so you will have to adjust it to make it do what you want it to do if that is the case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.