0

So I've 2 lists which come one of them comes from database, second one is updated with passed name later on. First list is fetched on @PostConstruct method when user displays a page, second list is updated for every name value from etiquette.

showClients.java bean with @ViewScoped value

     private List<Etiquette> etiquetteList;
     private List<Client> clientList;

    ...getters and setters 

       @PostConstruct
        public void init() {
            HttpSession session = SessionUtil.getSession();
            User user = (User) session.getAttribute("user");
            etiquetteList = etiquetteDAO.getAllEtiquettes(user);
            System.out.println(etiquetteList);
        }

        public List<Client> showClientsForEtiquette(String etiquetteName) {
            clientList = clientDAO.findClientsByEtiquetteName(etiquetteName);
            System.out.println(clientList);
            return clientList;
        }

For now everything works fine. I've etiquetteList and clientList are filled with data. Since I started working with those data for debbuging purposes I've done this

<h:form>
    <ui:repeat value="#{showClients.etiquetteList}" var="etiquette">
                        <p:panel id="horizontal" header="#{etiquette.name}" toggleSpeed="100" toggleable="true" toggleOrientation="vertical" collapsed="true" >  
                            <p:panelGrid columns="3" layout="grid" styleClass="showcase-text-align-center" >
                                <h:outputText value="Client name"/>
                                <h:outputText value="Client email"/>
                                <h:outputText value="Show details"/>
                            </p:panelGrid>
                            <p:panelGrid id="clientData" styleClass="showcase-text-align-center">
                                <ui:repeat value="#{showClients.clientList}" var="client">
                                    <p:panelGrid columns="3" layout="grid" styleClass="showcase-text-align-center" >
                                        <h:outputText value="#{client.name}"/>
                                        <h:outputText value="#{client.email}"/>
                                        <p:commandButton value="details" type="button" onclick="PF('clientDetails').show();" >
                                            <f:param name="client" value="client"/>
                                        </p:commandButton>
                                    </p:panelGrid>
                                </ui:repeat>
                            </p:panelGrid>
                        </p:panel>   
                    </ui:repeat>
    </h:form>

But this way is clumsy and I would like to display those data in very different way. I would like to display it in dataTable using PrimeFaces library to do so - I want functionality like toggleable ( toggleable in a way that you can just click on etiquette name and show/hide client information ), pagination, lazy fetch etc. As far as I have tried to implement that I have done this.

        <h:form id="groupForm">
                        <h:form>
                        <p:dataTable value="#{showClients.etiquetteList}" var="e" sortBy="#{e.name}" expandedRow="false"  expandableRowGroups="true"  rows="10"
                                     paginator="true"
                                     paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                                     currentPageReportTemplate="{startRecord}-{endRecord} of {totalRecords} records"
                                     rowsPerPageTemplate="5,10,15" >
                            <p:headerRow>
                                <f:facet name="header">
                                <p:column colspan="3">
                                    <h:outputLabel value="#{e.name}" />
                                </p:column>
                                </f:facet>
                            </p:headerRow>
                            <p:column colspan="3" style="margin: 20px 0;" >
                                <p:dataTable value="#{showClients.showClientsForEtiquette(e.name)}" var="c" lazy="true" expandedRow="false">
                                    <p:column headerText="Email">
                                        #{c.email}
                                    </p:column>
                                    <p:column headerText="Szczegóły">
                                        <p:commandButton value="Szczegóły"/>
                                    </p:column>
                                    <p:column  headerText="Usuń" >
                                        <p:commandButton value="Usuń"/>
                                    </p:column>
                                </p:dataTable>
                            </p:column>

                        </p:dataTable>
                    </h:form>

This is how I'd like to show my data. How can I approach this? I've read that you cannot set header of table because tables are generated row by row and the data isn't there yet to display as header. Any workarounds of that ? Also how can I make my table row ( this row with e.name ) to be toggleable? Use some panelGrid inside dataTable?

+----------------------------------------------------+
|                      e.name (value)                | 
+-----------------------------------------------------
| Email (string) | Detail (string) | Delete (string) |
|     c.email    |      button     |     button      |
Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Baniak
  • 25
  • 1
  • 6
  • Use the PrimeFaces 'p:overlay'? – Kukeltje May 12 '20 at 13:06
  • But I would like to display that table on subpage of my app constantly, and use p:overlay for details value for client, wouldn't that be a problem then ? – Baniak May 12 '20 at 13:13
  • if you want to use a subpage then use a subpage... It's all plain master-detail functionality. But then the title is in my opinion totally not related... See https://stackoverflow.com/questions/8459903/creating-master-detail-pages-for-entities-how-to-link-them-and-which-bean-scope. Please clarify your question – Kukeltje May 12 '20 at 13:31
  • But my question is related... I want to loop over 2 lists and in some specified way I want to show that data as dataTable to user but I don't know how to achieve what I specified – Baniak May 12 '20 at 13:45
  • Then my comment would be: "How would you do that if for displaying you'd use plain java and `System.out.println` right, you'd have to change the model server side. Do the same here... – Kukeltje May 12 '20 at 14:14
  • My problem is not with database structure and not having possibility how to extract needed information. I know how to extract data, I know how to display it. I don't know how to use in proper way to display in tableHeader value from first list and then as content (tableBody) display value from second list. As I show using ui:repeat I have access to this data, I don't know how to propery code dataTable to show it in a way I want to – Baniak May 12 '20 at 15:23
  • Where did I mention the database? I mean the model you use for the datatable. – Kukeltje May 12 '20 at 16:04
  • Why not use row-expansion and maybe make the whow row able to expand, not just the icon in front.... or use a subtable and add some small javascript to hide the subtable each time and open it... – Kukeltje May 13 '20 at 08:26

2 Answers2

0

I have posted answer, but after discussion in comment section with @Kukeltje I have decided to change some things. So here is a code.

<h:form id="groupsForm">
            <p:dataTable value="#{showClients.etiquetteList}" 
                         var="e" 
                         style="width: 80%; margin:0 auto;" 
                         paginator="true" 
                         rows="5" 
                         rowsPerPageTemplate="5,10,15,20,50" 
                         lazy="true" 
                         paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                         currentPageReportTemplate="{startRecord}-{endRecord} of {totalRecords} records">
                <p:column>
                    <p:growl id="msgs" showDetail="true" skipDetailIfEqualsSummary="true" />
                    <f:facet name="header">General header</f:facet>                    
                    <p:panel id="toggleable" header="#{e.name}" toggleable="true" toggleSpeed="500" collapsed="true" style="margin: 5px 0; border: 0;">
                        <p:ajax event="toggle" listener="#{showClients.onToggle}" update="msgs"/>
                        <p:panel toggleable="true" header="Client" toggleSpeed="500" collapsed="true" style="margin: 5px 0; border: 0;">                            
                            <p:dataTable value="#{e.clientCollection}" 
                                         var="c" 
                                         lazy="true" 
                                         paginator="true" 
                                         rows="5" 
                                         rowsPerPageTemplate="5,10,15,20,50"                                         
                                         paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                                         currentPageReportTemplate="{startRecord}-{endRecord} of {totalRecords} records"
                                         reflow="true"
                                         >
                                <p:column>
                                    <p:panelGrid columns="4" style="margin: 5px 0; border: 0;">   
                                        <p:column headerText="Name" priority="1">
                                            #{c.name}
                                        </p:column>
                                        <p:column headerText="Email" priority="1">
                                            #{c.email}
                                        </p:column>
                                        <p:column headerText="Email" priority="2">
                                            <p:commandButton value="Details"/>
                                        </p:column>
                                        <p:column headerText="Email" priority="3">
                                            <p:commandButton value="Delete"/>
                                        </p:column>
                                    </p:panelGrid>
                                </p:column>
                            </p:dataTable>
                        </p:panel>
                    </p:panel>
                </p:column>
            </p:dataTable>
        </h:form>

I am using PrimeFaces library. So what's change in comparison to your code. At first, I get rid of headerRow element and replaced it with <p:panel> in this way you can much more easier set a header of a panel which will be toggleable as well. In the facet element I have set general name of table - it's header. Next we have another <p:panel> - The reason why we have 2 panels is that you will be able to open first, and then open second containing list of clients. So now we have nested datatable. Both <p:dataTable> tables are used to get data from a list. It is very easy to use pagination and scrolling etc with those, you just add new parameters to dataTable attribute and it's all set. Every dataTable has to have <p:column> to display data so we use it to wrap <p:panelGrid> with our layout of page. As far as for <p:ajax> goes. We use it to show some popup message, whenever we toggle first panel. In your bean you should have a method which updates value using FacesMessage with even passed as parameter to ajax.
showClients.java toggle method

    public void onToggle(ToggleEvent event) {
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, event.getComponent().getId() + " toggled", "Status:" + event.getVisibility().name());
        FacesContext.getCurrentInstance().addMessage("groupsForm:msgs", message);
    }
Marcin
  • 102
  • 1
  • 2
  • 9
  • isn't double toggleable confusing for end-users? Personally I'd use row expansion and add some small one line of javascript and make clicking anywhere in the row expand the datatable – Kukeltje May 13 '20 at 08:27
  • I think double toggleable won't be confusing when you delete ``collapsed="true"`` from asecond panel, then when you toggle first panel you get loaded clients instatnly... I'm learning this stuff and that's the second idea which comes to my mind to implement :) – Marcin May 13 '20 at 08:46
  • That's what I was looking for. @Kukeltje you suggest using some JS to toggle second panel? I think he a little overused toggleable, I think I'll get rid of it and just show as regular panel with pagination enabled. – Baniak May 13 '20 at 08:57
-1
<h:form id="groupsForm">

            <p:dataTable value="#{showClients.etiquetteList}" var="e">
                <p:column>
                    <f:facet name="header">Some header</f:facet>
    <p:growl id="msgs" showDetail="true" skipDetailIfEqualsSummary="true" />
                    <p:panel id="toggleable" header="#{e.name}" toggleable="true" toggleSpeed="500" style="margin: 20px 0;">
                        <p:ajax event="close" listener="#{showClients.onClose}" update="msgs"/>
                        <p:ajax event="toggle" listener="#{showClients.onToggle}" update="msgs"/>
                        <p:repeat value="#{e.clientCollection}" var="c" >
                            <p:panelGrid columns="3" >
                                <p:column headerText="Email">
                                    #{c.email}
                                </p:column>
                                <p:column headerText="Detail">
                                    <p:commandButton value="Detail"/>
                                </p:column>
                                <p:column headerText="Delete">
                                    <p:commandButton value="Delete"/>
                                </p:column>
                            </p:panelGrid>
                        </p:repeat>
                    </p:panel>

                </p:column>
            </p:dataTable>
        </h:form>
Marcin
  • 102
  • 1
  • 2
  • 9
  • Why did you give me negative? On my screen it looks like what he want's to achieve – Marcin May 12 '20 at 17:16
  • 1
    There was a comment but it either got removed or I forget to press submit. It is because of a lack of textual context/explanation on what is added/changed and adding some text about limitations (OP has to add css to maybe hide the panel in some way that is does not become to crowded visually). Effectively there is just code... Cheers... Oh and a growl inside a datatable will result in weird behaviour – Kukeltje May 12 '20 at 19:09
  • 1
    Sorry for the missing comment! – Kukeltje May 12 '20 at 19:45
  • Ah, I see... Thank you @Kukeltje for pointing that out.. But the basic idea seems to be good right ? Or trying to solve that problem should I go to totally different direction ? One thing more I'd like to add is limitation of how many clients from clientCollection are being displayed to user, for example 10-20 clients at a time – Marcin May 12 '20 at 19:47
  • 1
    The basic approach of a toggleable panel can indeed work but I fail to see why you need ajax and update a msgs, and toggling, by default only works on the open/close icon (maybe not whay OP wants) and indeed OP misses some details about amount of 'children/details/clients' and also about real behaviour (confused me to in a way). Rowexpansion might be a solution too... – Kukeltje May 12 '20 at 20:54
  • I've just added ajax so user can see information about status of a panel. In bean there should be a method which displays corresponding state of toggling it's not required - if he won't need it he will delete it. – Marcin May 12 '20 at 20:58
  • 1
    That is why you should text explanations to it ;-) Please do, then I can remove the downvote (I want to ;-)) – Kukeltje May 12 '20 at 22:11
  • I've been working for another answer, which imo is much better ( in a way @Baniak wanted to display stuff ) with quite different syntax. Should I change this answer or post as new one and keep that one and just add explanations ? – Marcin May 12 '20 at 22:47
  • Add a new answer... Then maybe later this one can be removed. Chameleonizing this answer makes all comments look weird... – Kukeltje May 13 '20 at 00:18