function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
AdrianCCAdrianCC 

Problem with actionsuport and commandbutton - double click

Hello guys,

 

I need a little help.

 

I have a bug that goes like this: when the user edits an input field in an apex:repeat, and keeping the focus on the input goes with the mouse and clicks directly the Save button, only 1 ajax call is sent to the server, the one for the actionsupport of the inputField. Shouldn't 2 POSTs be made? one for the actionsupport that rerender a part of the table, and one for the {!save} action?

 

VF:

<apex:form>
	...
	<apex:commandButton action="{!save}" value="Save" rerender="existingProductsBlock,summaryTable,newProductsBlock" status="status" />
	...
	<apex:pageBlock>
		<apex:repeat value="{!fwrapper.wrapperList}" var="wrapper" >
			...
			<apex:outputPanel id="quantity" rendered="{!wrapper.isSelected}">
	   			<apex:actionRegion >
	                <apex:inputText value="{!wrapper.quantity}" style="width:30px;" onkeyup="return validate_qty(this);" >                                                                                                  
	                	<apex:actionSupport event="onchange"   reRender="existingProductsBlock" status="status"/>
	                </apex:inputText>
	            </apex:actionRegion>
	        </apex:outputPanel>
	        <apex:outputPanel id="quantity2" rendered="{!NOT(wrapper.isSelected)}">
	       		<apex:outputText value="{!wrapper.quantity}" style="width:30px;"  />
	        </apex:outputPanel>
	        ...

 The actionsupport is needed to rerender the list. This is because some fields influence the values of others, for example modifying quantity needs to modify the year1 values. 

public Decimal quantity							{
    		get; 
    		set {
    			if (quantity == value) {
    				return;
    			}
    			quantity = value;
    			if (quantity == null) {
    				quantity = 0;
    			}
    			if (listPrice == null) {
    				listPrice = 0;
    			}
    			if (discount == null) {
    				discount = 0;
    			}
    			year1 = listPrice*quantity*(100-discount)/100;
    			year2 = year1;
    			year3 = year1;
    			year4 = year1;
    			year5 = year1;
    			year6 = year1;	
    		}
    	}

 

So, in the page, when the user modifies a value, AND doesn't click anywhere else on the page, as in the cursor doesn't leave the input, BUT he goes directly to the save button, only the setting of that field occurs. The user needs to click again the save for it to occur...

 

Also, since the list of records is pretty large, or the instance is slow, idk, the setters are kinda slow. Setting a value, and waiting for the dependent fields to be modified in the controller takes some time. Is there some way to move this dependency logic in the client(javascript maybe?) so that the controller is not called on every input change?

 

Thank you,

Adrian

 

AdrianCCAdrianCC

Anyone?

Any little bit of help is appreciated :)

 

The closest similar problem that I've found on the interwebs was this: http://stackoverflow.com/questions/2166063/onblur-what-is-the-next-control-which-will-gain-focus

Yes, I know it's a generic js problem, but maybe someone can advise how to modify this for multiple, dynamic generated fields...

 

Happy weekend guys,

Adrian

joshbirkjoshbirk

Yeah, as you've noticed onChange for a text field is usually not fired until after the user has lost focus on the field.  I'd say you've got a couple of options:

 

  • You have a keyup event on the textField itself.  You might be able to define an actionFunction, instead of support, and call the Apex function from there.  But you'll probably want to refer to a "real" function (possibly your existing one) that can manage that traffic back.
  • Drop the actionSupport in lieu of a manual button which will perform the re-calc
  • Disable the submit button until you are satisified that the user has the right information before deciding to submit.  

The first bit, about throttling the events back to Apex with real JavaScript, might help with the speed issue as well.  If necessary, you might use something like jQuery with BlockUI to keep the user from changing values during server-side changes as well:

http://blogs.developerforce.com/developer-relations/2012/05/using-jquery-blockui-with-visualforce.html

AdrianCCAdrianCC

Hi Josh!

 

onkeyup event with server side processing doesn't sound too good, I'm afraid it will make a lot of calls.

 

Second option with the calculations being done client side should work. This is the way that I've been trying to do it till now, but I'm a little caught in the $Component ids(the table is rendered dynamically, and the elements are at different levels in the tree.

 

Third option sounds intriguing. And this might be the fastest fix, if the solution that I'm thinking of works. I'll try to put a disableButtons() js onfocus for all the inputFields. Donno if the users are going to like it :) but I'll try it and post here if it works...

 

About BlockUI, I'm already using jQuery dialog() set as a modal on an actionStatus when the server is processing. That was an earlier bug :).

 

Thank you very much for your time and advice, you're the first to reply. Kudos! 

 

PS: I've misread the second option, sorry... There are 3 separate actions on each line, based on a number of fields(qty, yr1 to y6 and discount). I don't want to add 3 buttons to each row of the table, at least for now

geosowgeosow

Is the {!save} calling a standard controller or a custom?

AdrianCCAdrianCC

Custom.

 

Edit: The page shows opportunity line items for an opportunity. A button with a custom link is used to get to it. The id of the Oppty is passed in the link and used in the constructor.

AdrianCCAdrianCC

Alright!

 

So I found a fix. The only problem is that I've stumbled upon a sfdc bug... so now I need a fix for the fix :).

 

I've started from the idea that while the inputFields are in edit(between onfocus and onblur-lose of focus- events) the action buttons, like {!save} should be disabled. This will force the user to click somewhere else in the page to trigger the onchange ajax call back to server(ffrom the actionsupport)

 

The fields now look like this(I'll post 1, but I've added the 2 js functions for all the inputs):

<apex:outputPanel id="quantity" rendered="{!wrapper.isSelected}">
                       			<apex:actionRegion >
		                            <apex:inputText value="{!wrapper.quantity}" style="width:30px;" onkeyup="return validate_qty(this);" onfocus="hidebuttons(this);" onblur="showbuttons(this);" >                                                                                                  
		                            	<apex:actionSupport event="onchange"   reRender="existingProductsBlock" status="status"/>
		                            	
		                            </apex:inputText>
	                            </apex:actionRegion>
                           </apex:outputPanel>

The js code:

<script type="text/javascript">
			function hidebuttons(comp) {
				var elem1 = document.getElementById("nobuttons1");
				var elem2 = document.getElementById("buttons1");
				var elem3 = document.getElementById("nobuttons2");
				var elem4 = document.getElementById("buttons2");
				
				elem1.style.display = "inline";
				elem2.style.display = "none";
				elem3.style.display = "inline";
				elem4.style.display = "none";
			}
			function showbuttons(comp) {
				var elem1 = document.getElementById("nobuttons1");
				var elem2 = document.getElementById("buttons1");
				var elem3 = document.getElementById("nobuttons2");
				var elem4 = document.getElementById("buttons2");
				
				elem1.style.display = "none";
				elem2.style.display = "inline";
				elem3.style.display = "none";
				elem4.style.display = "inline";
			}
		</script>

BUttons:

<div class="actionStatusClass" id="nobuttons2" style="display:none" >
        	<apex:commandButton action="{!recalculateSummaryTable}" disabled="true" value="Test Summary" rerender="summaryTable" status="status" /> &nbsp; &nbsp; &nbsp;
	        <apex:commandButton action="{!save}" disabled="true" value="Save" rerender="existingProductsBlock,summaryTable,newProductsBlock" status="status" /> &nbsp; &nbsp; &nbsp;
	        <apex:commandButton action="{!saveExit}" disabled="true" value="Save and Close" status="status" /> &nbsp; &nbsp; &nbsp;
	        <apex:commandButton value="Cancel" action="{!cancel}"/> &nbsp; &nbsp; &nbsp;
        </div>
		<div class="actionStatusClass" id="buttons2" >
			<apex:commandButton action="{!recalculateSummaryTable}" value="Test Summary" rerender="summaryTable" status="status" /> &nbsp; &nbsp; &nbsp;
	        <apex:commandButton action="{!save}" value="Save"  rerender="existingProductsBlock,summaryTable,newProductsBlock" status="status" /> &nbsp; &nbsp; &nbsp;
	        <apex:commandButton action="{!saveExit}" value="Save and Close" status="status" /> &nbsp; &nbsp; &nbsp;
	        <apex:commandButton action="{!cancel}" value="Cancel"/> &nbsp; &nbsp; &nbsp;      
        </div>

 

 

 

All is well, when the user clicks an input and starts pouring his heart's quantity out the buttons are disabled. He cannot click them directly.

 

Problem appears for 2 Date fields that I have... Seems for values of Date(or Lookup for that instance as well) the onfocus and onblur don't work on an apex:inputField :(

This is a know problem(for some time) from what I saw on the net. Don't know if it's design or just a bug. 

 

So I'm back to the drawing board, and I'm still open to suggestions!

 

Thank you,

Adrian