+ Start a Discussion
EnthEnth 

Using AJAX to select a row from a PageBlockTable

I've been struggling with the following problem, at heart I'm sure it's a simple error, but the behaviour is confusing and any explanation would be appreciated!

 

In general, I want to refresh a section of the page when a user clicks a row in a table. I would prefer not to use radio buttons or checkboxes. I've repeated the problem in a simple example below using the Account object for demonstration:

 

Visualforce Page:

<apex:page controller="TestActionController">
    <apex:form >
        <apex:pageBlock >
            <apex:outputPanel id="pan">
                <apex:outputText value="{!messy}" id="messyid"/>&nbsp;
                <apex:actionStatus startText="Selecting..." id="statusmsg"/>
            </apex:outputPanel>
            <apex:pageBlockTable value="{!accounts}" var="acc">
                <apex:actionSupport action="{!selectRow}" event="onclick" rerender="pan" status="statusmsg">
                    <apex:param name="selAccId" value="{!acc.Id}" assignTo="{!selectedId}" />
                </apex:actionSupport>                               
                <apex:column value="{!acc.Id}"/>
                <apex:column value="{!acc.Name}"/>            
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

 The custom controller:

public with sharing class TestActionController {

    public String messy {get; set;}
    public Id selectedId {get; set;}

    public TestActionController() {
        messy = 'Initialised';
    }

    public List<Account> getAccounts() {    
        return [SELECT Id, Name from Account LIMIT 10];
    }
    
    public PageReference selectRow() {
    
        this.messy = 'Clicked ' + this.selectedId + ' param selAccId is ' + ApexPages.currentPage().getParameters().get('selAccId');
        
        System.debug('>>> Clicked ' + this.selectedId);
        return null;
    }
    
}

 

The behaviour I'm seeing is:

  1. The status message is updated, implying the action has been fired, but the debug logs show the selectRow() method has not been fired.
  2. The debug log shows that when a row is clicked getAccts is fired TWICE

Would appreciate any guidance on better ways to do this, I though actionSupport would be simpler than using Javascript remoting, but I'm about to give up on it and switch.

Best Answer chosen by Admin (Salesforce Developers) 
bob_buzzardbob_buzzard

Hi Rich,

 

Inspecting the HTML generated by your page shows that the onclick handler has been attached to the table itself, rather than to each row, so the account id isn't known at that time.  I think that this is confusing things such that the form is simply submitted rather than being attached to an action, though I can't say for sure as I don't know how the javascript works in detail.

 

Changing the page markup to attach the onclick handler to each column as follows:

 

<apex:pageBlockTable value="{!accounts}" var="acc">
  <apex:column >
    <apex:actionSupport action="{!selectRow}" event="onclick" rerender="pan" status="statusmsg">
      <apex:param name="selAccId" value="{!acc.Id}" assignTo="{!selectedId}" />
    </apex:actionSupport>                               
    <apex:outputText value="{!acc.Id}" />            
  </apex:column>
  <apex:column >
    <apex:actionSupport action="{!selectRow}" event="onclick" rerender="pan" status="statusmsg">
      <apex:param name="selAccId" value="{!acc.Id}" assignTo="{!selectedId}" />
    </apex:actionSupport>
    <apex:outputText value="{!acc.Name}" />            
  </apex:column>                               
</apex:pageBlockTable>

 

means that it works as expected, although it introduces the downside of some repeated code.

 

WRT getAccounts being called twice - multiple calls to getters when rendering a page is documented behaviour and my understanding of how the AJAX request works is that the entire page is reconstructed, but only the sections being rerendered are then applied to the DOM.  

 

All Answers

bob_buzzardbob_buzzard

Hi Rich,

 

Inspecting the HTML generated by your page shows that the onclick handler has been attached to the table itself, rather than to each row, so the account id isn't known at that time.  I think that this is confusing things such that the form is simply submitted rather than being attached to an action, though I can't say for sure as I don't know how the javascript works in detail.

 

Changing the page markup to attach the onclick handler to each column as follows:

 

<apex:pageBlockTable value="{!accounts}" var="acc">
  <apex:column >
    <apex:actionSupport action="{!selectRow}" event="onclick" rerender="pan" status="statusmsg">
      <apex:param name="selAccId" value="{!acc.Id}" assignTo="{!selectedId}" />
    </apex:actionSupport>                               
    <apex:outputText value="{!acc.Id}" />            
  </apex:column>
  <apex:column >
    <apex:actionSupport action="{!selectRow}" event="onclick" rerender="pan" status="statusmsg">
      <apex:param name="selAccId" value="{!acc.Id}" assignTo="{!selectedId}" />
    </apex:actionSupport>
    <apex:outputText value="{!acc.Name}" />            
  </apex:column>                               
</apex:pageBlockTable>

 

means that it works as expected, although it introduces the downside of some repeated code.

 

WRT getAccounts being called twice - multiple calls to getters when rendering a page is documented behaviour and my understanding of how the AJAX request works is that the entire page is reconstructed, but only the sections being rerendered are then applied to the DOM.  

 

This was selected as the best answer
EnthEnth

Thanks Keir, that does the trick. Instead of adding it for every column I think I'll add an icon for display they can click on so it's a better visual cue too.

RussYoungRussYoung
Well, it's Feb 2014 and this solution solved my problem .... after 2 days worth of searching.

Thanks!!

Russ


VempallyVempally
Is the selection possible only through ID....