Question

This is my the escenario:

A h:dataTable with a HtmlDataTable object binding in the backed bean. Calling a getClientId for the HtmlDataTable in an action method fired by a command button inside of a h:column is give me the data table id and the row index as clientId. If the data table id is 'table', the getClientId() is returning table:0 (or table:1, table:2 ... depending of the row index where the command button is)

I expect get just 'table' as clientId, since the table binded is always the same.

When I call the same method with a button that is outside of the data table, I get 'table'. That is correct for me but I don't understand why if the action comes from a UIColumn button I'm getting table:rowIndex.

The JSF Page is:

 <h:form prependId="false">
        <h:dataTable id="table" value="#{sessionBean.dummyData}" var="row" binding="#{sessionBean.dataTable}">
            <h:column>
                <f:facet name="header">
                    ROW ID
                </f:facet>
                #{row.longValue()}
            </h:column>

            <h:column>
                <f:facet name="header">
                    ACTION 1
                </f:facet>
                <h:commandButton id="btn1" value="REFRESH CLIENT FROM UIColumn" >
                    <f:ajax execute="@this" render="output" listener="#{sessionBean.testAction()}" />
                </h:commandButton>
            </h:column>
        </h:dataTable>

        <h:commandButton id="btn2" value="REFRESH CLIENT outside from data table" >
                    <f:ajax execute="@this" render="output" listener="#{sessionBean.testAction()}" />
        </h:commandButton>


        <h:outputText id="output" value="#{sessionBean.clientId}" />
    </h:form>

Backed Bean:

@ManagedBean
@SessionScoped
public class SessionBean {
    private List<Long> dummyData;
    private String clientId;
    private HtmlDataTable dataTable;


    public SessionBean() {
        dummyData = new ArrayList<Long>();
    }

    @PostConstruct
    public void postConstruct(){
        for(int i = 0; i < 5; i++){
            dummyData.add(new Long(i));
        }
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public void testAction(){
        clientId = this.dataTable.getClientId();
    }

    public List<Long> getDummyData() {
        return dummyData;
    }

    public void setDummyData(List<Long> dummyData) {
        this.dummyData = dummyData;
    }

    public HtmlDataTable getDataTable() {
        return dataTable;
    }

    public void setDataTable(HtmlDataTable dataTable) {
        this.dataTable = dataTable;
    }
}

Thanks in advance. I would like to know if this is the normal JSF behaviour.

Was it helpful?

Solution

I have done some JSF code digging and, yes, it seems that they have intentionally designed it to work this way. During the JSF lifecycle processing on the server, the clientId of the HtmlDataTable object continuously changes, since it includes the index of the "currently selected" row. And, in the 'Invoke Application' lifecycle phase, shortly before invoking the Ajax handler (i.e. the 'testAction' method), the JSF framework sets the row index of the HtmlDataTable to correspond to the row on which the clicked button is located.

As far as I understand from the JavaDoc of the UIData::getClientId(FacesContext) method (which is inherited by HtmlDataTable) the rationale, for including the row index in the clientId of UIData components, is to avoid clientId collision between child components that belong to different rows.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top