+ Start a Discussion
MellowRenMellowRen 

ActionSupport’s OnChange vs the Save button

I have a InputText object with an embedded ActionSupport that activates with the OnChange event to call a method from the Controller Extension. In reduced form here:

 

<apex:pageBlockSection showHeader="True" columns="2" title="Pricing" id="pricingBlock”>
   <apex:pageBlockSectionItem >
      <apex:outputLabel value="Discount" for="discProxy"/><apex:inputText value="{!discountText}" id="discProxy”>
         <apex:actionSupport event="onchange" 
                             action="{!afterDiscChange}" 
                             rerender="pricingBlock" />
      </apex:inputText>
   </apex:pageBlockSectionItem>
</apex:pageBlockSection>

 

It works perfectly except when someone changes the value in the text field and then immediately clicks on the Save button (or hits return which invokes the Save button). ie Does not click (or tab) elsewhere first. In this case, the code in afterDiscChange() is not executed and since it is meant to change a field value that we subsequently want saved it leads to an unwanted/unexpected result.

 

I tried replacing onchange with onblur but got the same (non)result.

 

Anyone come across this problem? Got any ideas on what I can do here? The simpler the better but I am not shy on doing coding if that's what it takes.

 

Further Information: I actually have more than one ActionSupport enabled InputText in this PageBlockSection, each with its own individual method attached. All work fine but are likewise not called if the Save button is immediately pressed. The methods are mutually destructive so I can't simply call them all as part of the save process. I could have the save method call the correct one if I had a way of determining which specific InputText was the one that was edited (assuming, of course, the just changed value of discountText is actually passed back to the Extension—might go System.Debug that to have a look).

 

 

Best Answer chosen by Admin (Salesforce Developers) 
AdrianCCAdrianCC

Okay, let's try adding a modal for the onchange action. A jquery shown/hidden div that blocks the whole page while your action takes place. This will be started in the apex:actionstatus

<apex:includeScript value="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" />
    <apex:includeScript value="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js" />
    <apex:stylesheet value="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/redmond/jquery-ui.css" />
    
    <apex:outputPanel id="opHelper">
        <script>
         
            ////////////////////////////
            // Always declare another instance of jQuery as not to conflict with SF's instance
            ////////////////////////////
            var j$ = jQuery.noConflict();
            
            ////////////////////////////
            // Wait for document.ready
            ////////////////////////////
            j$(document).ready(function(){
                j$( "#dialog-modal" ).dialog({
                    autoOpen: false,
                    height: 120,
                    width:  210,
                    modal: true,
                    resizable: false,
                    draggable: false,
                    closeOnEscape: false,
                    show: "puff",
                    hide: "puff"
                });
                
            });
            
            function statusShow() {
                j$( "#dialog-modal" ).dialog( "open" );
            }
            
            function statusHide() {
                j$( "#dialog-modal" ).dialog( "close" );
            }
...

 The modal itself:

<div id="dialog-modal" title="Refreshing Page">
            <p>
                <table style="vertical-align:middle;color:royalblue;font-size:11pt;font-weight:bold;" >
                    <tr>
                        <td><img src="{!$Resource.AjaxLoader}" border="0" /></td>
                        <td style="color:royalblue" > &nbsp;Please Wait...</td>
                    </tr>
                </table>
            </p>
        </div>

 AjaxLoader is a spinning gif... put some text if you don't like it

 

The actionStatus will use onstart & onstop(check docs):

<apex:actionStatus id="status" startText="Processing ... " onstart="statusShow();" onstop="statusHide();" />

 For the actionSupport try using onblur, onchange is kinda **bleep**ed up in IE. Experiment with different events

Also take a look at the focus attribute of the actionSupport, I know this happens after the action but maybe you want to point the user at some other field in the page

 

That's it! Keep it up and don't surrender to bugs :)

Adrian

 

 

 

 

All Answers

AdrianCCAdrianCC
Hello,

Try to add the status attribute to the actionsupport with a corresponding actionStatus.http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_actionStatus.htm

Ty,
Adrian
MellowRenMellowRen

Adrian

 

I have to admit, I can't figure out why that would help the situation.

 

I am going to try it right away.

 

Regards

MellowRen

MellowRenMellowRen

Unfortunately no go. As I clicked the Save I could see the visual effect of "Incrementing" being done before the page refreshed (which had me very excited) but the method was still not being called. Thank you for the idea anyway.

AdrianCCAdrianCC

Okay, let's try adding a modal for the onchange action. A jquery shown/hidden div that blocks the whole page while your action takes place. This will be started in the apex:actionstatus

<apex:includeScript value="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" />
    <apex:includeScript value="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js" />
    <apex:stylesheet value="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/redmond/jquery-ui.css" />
    
    <apex:outputPanel id="opHelper">
        <script>
         
            ////////////////////////////
            // Always declare another instance of jQuery as not to conflict with SF's instance
            ////////////////////////////
            var j$ = jQuery.noConflict();
            
            ////////////////////////////
            // Wait for document.ready
            ////////////////////////////
            j$(document).ready(function(){
                j$( "#dialog-modal" ).dialog({
                    autoOpen: false,
                    height: 120,
                    width:  210,
                    modal: true,
                    resizable: false,
                    draggable: false,
                    closeOnEscape: false,
                    show: "puff",
                    hide: "puff"
                });
                
            });
            
            function statusShow() {
                j$( "#dialog-modal" ).dialog( "open" );
            }
            
            function statusHide() {
                j$( "#dialog-modal" ).dialog( "close" );
            }
...

 The modal itself:

<div id="dialog-modal" title="Refreshing Page">
            <p>
                <table style="vertical-align:middle;color:royalblue;font-size:11pt;font-weight:bold;" >
                    <tr>
                        <td><img src="{!$Resource.AjaxLoader}" border="0" /></td>
                        <td style="color:royalblue" > &nbsp;Please Wait...</td>
                    </tr>
                </table>
            </p>
        </div>

 AjaxLoader is a spinning gif... put some text if you don't like it

 

The actionStatus will use onstart & onstop(check docs):

<apex:actionStatus id="status" startText="Processing ... " onstart="statusShow();" onstop="statusHide();" />

 For the actionSupport try using onblur, onchange is kinda **bleep**ed up in IE. Experiment with different events

Also take a look at the focus attribute of the actionSupport, I know this happens after the action but maybe you want to point the user at some other field in the page

 

That's it! Keep it up and don't surrender to bugs :)

Adrian

 

 

 

 

This was selected as the best answer
MellowRenMellowRen

AdrianCC

 

Thanks for this. I was implimenting it when it suddenly occured to me how to fix my problem using Apex code in the Extension—and it was annoyingly simple in the end.

 

Your solution was working though.

 

Regards

MellowRen

AdrianCCAdrianCC

Can you please post your solution here? For future reference :)

 

Happy Friday,

Adrian

MellowRenMellowRen

Yeah fair enough. In simplified form this is what I did:

 

private string discountTextOld; //added this

//Method called by actionSupport
public PageReference afterDiscChange() {
    doLotsOfCalculationsAndStuff();
    discountTextOld = discountText; //added this
    return null;
}

//Exit Method
public PageReference customSave() {
    if (discountText != discountTextOld) {afterDiscChange();} //added this
    doSaveRelatedStuff();
    return stdCtrller.save();
}

 Sigh :-/  So simple. No idea why I didn't think of this from the outset.

boBNunnyboBNunny

I have a similar issue, but this fix won't work for me because I need to know what the changed value was.  The event onChange fires, never actually fires.  Upon tabbing off or clicking somewhere else it does, but when clicking Save or any pagination link, it does not.

AdrianCCAdrianCC

Hello @boBNunny,

 

Can you post your code here?

 

Ty,

Adrian