[SalesForce] Button redirects page before async call is finished in another field

I am really confused as to how to solve this issue I have on a visualforce page. Basically I have a pageblock table with some Opportunity Products displayed. On the onchange event of the fields in the rows I have placed an actionsupport tag that will call a save method then rerender the row so that the updated TotalPrice from the server can be displayed.

My issue is that IF I make change to one of these fields then immediately click a Finish button (this button contains a redirect to the Opp) the redirect is executed instantly, the async call from the onchange event is not completed BEFORE the redirect (since its async) and therefore the Opp is displayed before the Opportunity is updated meaining I have to reload the Opp page to see the updated Amount.

What I want is a way to have the actionsupport tag of the inputfields complete before the redirect of the Finish button is executed. How can I acomplish this???

Please help as I am out of ideas, I have tried several things and they all have not worked.

Best Answer

I think the user clicks on the Save button before the AJAX call is finished and the record is not saved, right? My solution is just to block the input elements on the page while the AJAX call works, and only if it finished - release the inputs. So user can not click on the Save button while your controller works.

Simple controller example:

public with sharing class test1 {
    // We will show some account on the page
    public List<Account> accounts { get; set; }

    public test1(){
        // Reading accounts
        accounts = [Select Id, Name, CustomerPriority__c From Account Limit 3];
    }

    public PageReference someAction(){
        // Your 'save' logic is here ....
        return null;
    }
}

Visualforce page. I will use JQuery to block the input elements on the page:

<apex:page controller="test1">
    <!-- Dynamically including the jQuery to the page -->
    <apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"/>

    <!-- This is a javascript function that will block and release elements -->
    <script>
        function blockAllInputs(param){
            if(param){
                jQuery('input[type=button], input[type=submit]').attr('disabled','disabled').removeClass('btn').addClass('btnDisabled');
                jQuery('select').attr('disabled','disabled');
            }
            else{
                jQuery('input[type=button], input[type=submit]').removeAttr('disabled').removeClass('btnDisabled').addClass('btn');
                jQuery('select').removeAttr('disabled');
            }
        }
    </script>

    <apex:form>
        <apex:pageBlock title="My Block">
            <apex:pageBlockButtons>
                <apex:commandButton value="Save" reRender="none"/>
            </apex:pageBlockButtons>
            <apex:pageBlockTable value="{!accounts}" var="a">
                <apex:column headerValue="{!$ObjectType.Account.fields.CustomerPriority__c.label}">
                    Value: 
                    <apex:actionRegion>
                        <apex:inputField value="{!a.CustomerPriority__c}" id="myField">
                            <apex:actionSupport event="onchange"
                                                action="{!someAction}"
                                                reRender="myField"
                                                onsubmit="blockAllInputs(true)"
                                                oncomplete="blockAllInputs(false)"/>
                        </apex:inputField>
                    </apex:actionRegion>
                </apex:column>            
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

How it will looks like:

enter image description here