+ Start a Discussion
MellowRenMellowRen 

Possible to determine current focus?

HI

 

I have a page that needs to do the occasional calculation then show the results afterwards which entails a section of the page to be rerendered. If the focus was within the rerendered area then the focus is lost. I want to put it back. I am aware that a lot of components that have an Action attribute also have a Focus attribute. Problem is I can't figure out how to tell it to return the focus to where it was. I am hoping that there is something like this:

 

focus="{!$CurrentPage.getComponentID.CurrentFocus}"

 

That would make life so easy. Not afraid of APEX or Javascript if they present a solution. Any and all help appreciated.

 

Regards

MellowRen

Best Answer chosen by Admin (Salesforce Developers) 
JayNicJayNic

Apex will not help - it's not client side. Visualforce also does not have such a function.

 

My solution would be to store what element was in focus at the time the re-render was called.

 

for example:

<script>
   var elementFocus = null;

   function retainFocus(){
       elementFocus.focus();
   }
</script>


<apex:actionfunction name="af_myFunctionCall" onbeforedomupdate="elementFocus = document.activeElement" rerender="myComponentId" oncomplete="retainFocus()"/>

 This way you store what you were focusing on before the transaction, then set it afterward

Just make sure you don't rerender the area of the page with the script in it of courcse

All Answers

JayNicJayNic

Apex will not help - it's not client side. Visualforce also does not have such a function.

 

My solution would be to store what element was in focus at the time the re-render was called.

 

for example:

<script>
   var elementFocus = null;

   function retainFocus(){
       elementFocus.focus();
   }
</script>


<apex:actionfunction name="af_myFunctionCall" onbeforedomupdate="elementFocus = document.activeElement" rerender="myComponentId" oncomplete="retainFocus()"/>

 This way you store what you were focusing on before the transaction, then set it afterward

Just make sure you don't rerender the area of the page with the script in it of courcse

This was selected as the best answer
MellowRenMellowRen

JayNic

 

Thanks for your reply. Your solution partially worked for me. I have been playing but can't seem to get  it to go. Here is a reduced version of my VF page:

 

<apex:dataTable value="{!extOLIs}" var="e" id="pricingBlock" rowClasses="odd,even" styleClass="tableClass">
    <apex:column headerValue=“Huntsman">
        <apex:inputText value="{!e.huntText}" id=“huntPr">
            <apex:actionSupport event="onchange" action="{!e.afterHuntChange}" onbeforedomupdate="elementFocus = document.activeElement" rerender=“huntPr,fredPr,errorMessages" oncomplete="retainFocus()" />
         </apex:inputText>%
    </apex:column>
    <apex:column headerValue="Price">
         <apex:inputText value="{!e.salesPriceText}" id="fredPr">
             <apex:actionSupport event="onchange" action="{!e.afterPriceChange}" onbeforedomupdate="elementFocus = document.activeElement" rerender=“huntPr,fredPr,errorMessages" oncomplete="retainFocus()" />
         </apex:inputText>
     </apex:column>
</apex:dataTable>

<apex:outputPanel styleClass="search">Type in: </apex:outputPanel>
<apex:inputText value="{!searchString}" id="sText"/>

 

As you can see, the big difference is that I (had to?) use an ActionSupport rather than ActionFunction. If I change the value in either huntPr or fredPr, and then click in the other, the focus is lost after the rerender.

 

If instead I click in sText (which is also rerendered) the focus survives! I have tried rerendering pricingBlock rather than the fields, I get the same problem.

 

Any ideas?

 

Regards

MellowRen

JayNicJayNic

Since VF dynamically creates element ids and names on the fly, they might be changing for some reason after a re-render...

 

Try some alerts like so to see if the element is still there.

 

<script>
   var elementFocus = null;

   function retainFocus(){
       alert('Attempting to find stored id: ' + document.getElementById(elementFocus.id));
       elementFocus.focus();
       
   }
</script>



<apex:dataTable value="{!extOLIs}" var="e" id="pricingBlock" rowClasses="odd,even" styleClass="tableClass" id="theTable">
    <apex:column headerValue=“Huntsman">
        <apex:inputText value="{!e.huntText}">
            <apex:actionSupport event="onchange" action="{!e.afterHuntChange}" onbeforedomupdate="elementFocus = document.activeElement; alert('The ID I am storing is: ' + document.activeElement.id);" rerender=“theTable,errorMessages" oncomplete="retainFocus()" />
         </apex:inputText>%
    </apex:column>
    <apex:column headerValue="Price">
         <apex:inputText value="{!e.salesPriceText}" >
             <apex:actionSupport event="onchange" action="{!e.afterPriceChange}" onbeforedomupdate="elementFocus = document.activeElement" rerender=“theTable,errorMessages" oncomplete="retainFocus()" />
         </apex:inputText>
     </apex:column>
</apex:dataTable>

 

 

Also note that I changed your re-renders. You can just re-render the whole table since you're re-rendering all the dynamic bindings anyways.

 

If this doesn't work, then I would use 'document.getElementsByClassName' and give each of your input elements a unique class name eg: 

<apex:inputText value="{!e.huntText}" styleClass="huntText">

and use document.getElementsByClassName('huntText')[0];

since you know that the style class will retain through the re-render. So rather than storing the active element, you just store the active elements class name, then re-query for it in the 'retainFocus' function.

MellowRenMellowRen

JayNic

 

After a lot of playing around I finally got it to work. For the sake of completeness I'll put some notes here.

 

  1. If I use your code and have the rerender include the whole datatable then the current focus is maintained if it was outside the datatable but not if it was inside [nothing ends up being in focus].
  2. If the rerender includes all the required inputTexts and outputTexts (my actual page has these as well) within the datatable individually and not the datatable itself, then the current focus is maintained if the user clicks on any input element on the page, inside or outside the datatable, but the focus is not maintained if the user tabs out of the original cell.
  3. If I add a focus attribute to the actionSupport element and point it to the input element that a tab goes to then the focus is maintained after a tab and, happily enough, the focus is also still correct after a mouse click change thanks to your code.

Why does 3 work like that? I have no idea, doesn't make sense to me. Can't complain though since it does what I want :-)

 

Thank you for your help (and js knowledge).

 

Regards

MellowRen

NikiVankerkNikiVankerk
Thanks JayNic, this is exactly what I've been hunting for.  The only tweak I needed to get the focus to reset was getting the element again in the reset focus: 
function retainFocus(){
           document.getElementById(elementFocus.name).focus();
       }
Not really sure why elementFocus.focus() didn't work but this change got things going.  Awesome.