0

EDIT: 2017-04-28 The exact same problem (different circumstances/application) is described here: Process f:viewParam only on page load


Primefaces 6.1.RC2

JSF Mojarra 2.3.0


I already have a Java backing-bean based workaround (explained below) for the problem the following behaviour of p:dataTable causes, but I am not very happy with that workaround, and I would like to understand the behavior of p:dataTable row editing better and if possible I would like to find a purely XHTML-level solution to my problem. (BTW I am otherwise very experienced with p:dataTable, which I have used for some very complex applications for some years.)

It is not about an error or bug in p:dataTable, but the way it behaves during row editing causes me a problem in one situation.

The following code examples are completely simplified and adapted for this forum.

I have an entity Element, which has a relationship List<Link> getLinks(), where Link is also an entity.

Element has an editor edit.xhtml.

The aim is to have an composite component links_editor.xhtml that can be embedded in the edit.xhtml.

There is a CDI-compliant @ViewScoped @Named backing bean Manager.

The edit.xhtml relies on an f:viewParam to load an Element for editing:

<f:view>
    <f:metadata>
       <f:viewParam name="id" value="#{manager.id}"/>
    </f:metadata>
</f:view>

Where in the backing bean Manager:

public void setId(Long id) {
    if (id != null) {
      //load an Element from database for editing by id

And in the links_editor.xhtml:

<cc:implementation>
    <div id="#{cc.clientId}">

                <p:growl id="testgrowl"/>

                <p:dataTable
                    id="links_table"
                    editable="true"                    
                    var="link"
                    value="#{cc.attrs.element.links}"
                    >   

                    <p:ajax 
                        event="rowEdit" 
                        listener="#{cc.attrs.manager.onLinkRowEdit}"
                        update="#{cc.clientId}:testgrowl"
                        />

                    <p:column headerText="Link title">
                        <p:cellEditor>
                            <f:facet name="output">
                                <h:outputText value="#{link.name}" />
                            </f:facet>
                            <f:facet name="input">
                                <p:inputText id="name" value="#{link.name}"/>
                            </f:facet>
                        </p:cellEditor>                        
                    </p:column>

                    <p:column headerText="Link URL">
                        <p:cellEditor>
                            <f:facet name="output">
                                <h:outputText value="#{link.urlAsString}" />
                            </f:facet>
                            <f:facet name="input">
                                <p:inputText id="url" value="#{link.urlAsString}"/>
                                <p:message 
                                    for="url" 
                                    display="icon"                                        
                                    />
                            </f:facet>
                        </p:cellEditor>                        
                    </p:column>
                    <p:column>
                        <p:rowEditor />
                    </p:column>                    
                </p:dataTable>

The row edit listener:

public void onLinkRowEdit(RowEditEvent event) {
    Link link = (Link) event.getObject();
    try {
        checkLink(link); //throws if URL string malformed         
        JsfUtil.addInfoMessage("DEBUG: Link: "+link);
    } catch (LocalUpdateException ex) {
        JsfUtil.addErrorMessage(ex.getMessage());
    }
}

(where JsfUtil obviously just leverages FacesContext.getCurrentInstance().addMessage(...))

The issue/concern:

If I edit a Link row in the p:dataTable a first time and then use the "tick save" the onLinkRowEdit listener is invoked, but the diagnostics show that the value appear not to have changed. The reason is that this f:viewParam is invoked:

       <f:viewParam name="id" value="#{manager.id}"/>

This (via routes not shown in detail) loads the Element entity again from database via setId(Long id), so that in the composite component edit_links.xthml this essentially resets #{cc.attrs.element.links}, so any changes are discarded.

The interesting thing is that if (without reloading the entire @ViewScoped page) one edits the same p:dataTable row a second time that f:viewParam is NOT invoked, and thereafter it works as desired.

A workaround (rather hacky) is to "block" any attempt to reload the Element by id within the view scope backing bean Manager:

public void setId(Long id) {

   //HACK/WORKAROUND: prevent reload of Element by id
   if (Objects.equals(id, this.id)) {
       return;
   }

    if (id != null) {
      //load an Element from database for editing by id

To be clear, I am aware of the usual strategies for using @PostConstruct and/or lazy database fetching in getters of frequently accessed info under JSF in backing beans. And I don't want to abandon here the f:viewParam approach entirely (and it works well for other situations the same Manager bean is also used for).

My interest is specifically about Primefaces p:dataTable:

Q1: Why does p:dataTable need to call the f:viewParam during the 1st row edit then "tick save", when the row information (in this cases element.links) is clearly already available ?

Q2: Why does p:dataTable NOT need to call the f:viewParam during the 2nd row edit then "tick save" ?

Q3: Is there a JSF XHTML-based way of preventing p:dataTable from calling the f:viewParam at all during a rowEdit then "tick save" (including the 1st go) ?


UPDATE: 2017-04-21: There is now a mini test web app for NetBeans 8.2 demonstrating the problem at:

https://github.com/webelcomau/Webel_PrimeFaces_test_p50445_dataTable_fviewParam

Please just download the master ZIP-archive, unzip it, and open it in NetBeans IDE 8.2. You don't need to Git-clone the project. Make sure you have Glassfish-4.1.1 set as the server for the project.

Both the README there and the web app test page itself give precise steps for reproducing the problem (or the behavior that concerns me).

I have invested some effort in analysing this because I use p:dataTable "embedded" in edit forms together with f:viewParam a lot, and I want to understand this matter better, even if it is not an actual problem with p:dataTable.

Community
  • 1
  • 1
  • My Q's: Does the same happen with PF 6.0 and/or JSF 2.2? How do you know the `p:datatable` calls the viewparam and not something the JSF impl does (in other words, who is the culprit) Does the same happen when not using a custom component? Are there fundamental differences in what is posted from the client to the server? And do you have an [mcve] so I can try to reproduce – Kukeltje Apr 14 '17 at 10:01
  • @Kukeltje Good questions. I know same happened with PF6.0 and JSF 2.3.0-m07 (would need test case for earlier since main/real web app not compatible with earlier JSF version). I know that performing the first (only) p:dataTable rowEdit then "tick save" _triggers_ the the f:viewParam to be invoked because I can see it logged in setId(Long); I can try in NetBeans debugger might show more of the sequence (i.e. something JSF impl does). Will prepare a minimal example with a comparison of within CC vs outside in standalone h:form (but might be over this weekend, probably not tonight Sydney time). – Webel IT Australia - upvoter Apr 14 '17 at 10:36
  • Thanks, no problem... And it is a looooooong wekend in Utrecht/Amsterdam (monday is a holiday) – Kukeltje Apr 14 '17 at 10:37
  • @Kukeltje [Mini test web app for NetBeans 8.2 on GitHub clearly demonstrating the issue/concern/behaviour](https://github.com/webelcomau/Webel_PrimeFaces_test_p50445_dataTable_fviewParam), grateful for any feedback. – Webel IT Australia - upvoter Apr 21 '17 at 10:08
  • The exact same problem (different circumstances/application) is described here: [Process f:viewParam only on page load](http://stackoverflow.com/questions/23903351/process-fviewparam-only-on-page-load) – Webel IT Australia - upvoter Apr 28 '17 at 02:28

0 Answers0