p:dataTable how prevent f:viewParam being invoked on 1st rowEdit then tick save using JSF at XHTML level (not in bean)

Components, Ajax Framework, Utilities and More.
Post Reply
webel
Posts: 84
Joined: 18 Sep 2010, 09:29
Location: Sydney, Australia
Contact:

14 Apr 2017, 11:18

[EDIT 2017-04-24: now also as PrimeFaces community issue report. https://github.com/primefaces/primefaces/issues/2299 and with easy NetBeans 8.2 test app]

Hi PrimeFaces forum,

I have a Java backing-bean based workaround (explained below) for the problem the following behaviour 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 relation 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 which can be embedded in the edit.xhtml.

There is a CDI-compliant @VIewScoped backing bean Manager.

The edit.xhtml relies on a 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:

Code: Select all

    public void setId(Long id) {
        if (id != null) {
          //load an Element from database for editing by id
In the links_editor.xhtml:

Code: Select all

    
    <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:

Code: Select all

    
    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 above obviously just leverages FacesContext.getCurrentInstance().addMessage(...) for diagnostics.

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:

Code: Select all

 
 <f:viewParam name="id" value="#{manager.id}"/>
This (via routes not shown in detail) loads the Element again from database via setId(Long id), so that in the composite component edit_links.xthml this is essentially reset #{cc.attrs.element.links}, 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:

Code: Select all

 
 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 for frequently accessed info under JSF in backing beans. And I don't want to abandon here the f:viewParam approach entirely (as 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 case 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 an XHTML-base way of preventing p:dataTable from calling the f:viewParam at all during rowEdit and "tick save" ?
Last edited by webel on 24 Apr 2017, 14:41, edited 1 time in total.
Primefaces 6.1
JSF Mojarra 2.3.0
(Netbeans 8.2+Glassfish 4.1.1 OR Payara 4.1)
Mac OS X "Yosemite" 10.10.5 / Linux CentOS 6.7

kukeltje
Expert Member
Posts: 8473
Joined: 17 Jun 2010, 13:34
Location: Netherlands

14 Apr 2017, 12:25

Ronald van Kuijk
______________________________
PrimeFaces 5.2, PrimeFaces plus 0.0.2 | JbossWildfly 8.1| Mojarra 2.2.8
Fedora 21, Firefox 'most recent'
Read the forum posting rules
Beginners: https://jsf.zeef.com/bauke.scholtz

webel
Posts: 84
Joined: 18 Sep 2010, 09:29
Location: Sydney, Australia
Contact:

21 Apr 2017, 12:01

There is now a mini test web app for NetBeans 8.2 demonstrating the problem at:

https://github.com/webelcomau/Webel_Pri ... 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.
Primefaces 6.1
JSF Mojarra 2.3.0
(Netbeans 8.2+Glassfish 4.1.1 OR Payara 4.1)
Mac OS X "Yosemite" 10.10.5 / Linux CentOS 6.7

Post Reply
  • Information