I have a problem with data in a <p:rowExpansion> being loaded before the row is expanded (which leads to loads of web service requests).
I am using PrimeFaces 5.2. I have a dataTable with lazy loading and pagination. Inside of the table, I have <p:rowToggler> with a <p:rowExpansion>:
<p:dataTable var="order"
widgetVar="orderTable"
lazy="true"
value="#{ordersBean.orders}"
paginator="true"
rows="20"
rowsPerPageTemplate="20,50,100"
filterDelay="300"
styleClass="filtered">
<p:column width="4%">
<p:rowToggler />
</p:column>
<p:column headerText="Order number" width="96%">
<h:outputText value="#{order.number}" />
</p:column>
<p:rowExpansion>
<h:panelGrid columns="1">
<h:outputText value="#{order.number}" />
<h:outputText value="#{order.info}" />
<h:dataTable var="item" value="#{ordersBean.getItemsInOrder(order.number)}">
<h:column>
<h:outputText value=" #{item.title}" />
</h:column>
</h:dataTable>
</h:panelGrid>
</p:rowExpansion>
</p:dataTable>
When I first load the page, the getItemsInOrder() method is not called, except for when I expand a row. But if I navigate to page 2 (or if I navigate back to page 1 later) using the paginator, then getItemsInOrder() is called for every row in the outer table. Since I have 20 rows showing, navigating between the pages leads to 20 web service requests (in getItemsInOrder()).
How do I prevent it from calling the getItemsInOrder() method until the row is expanded?
I have the same problem. Until I find a better solution, this is the workaround I am using:
register a (DataTable event-) listener on event rowToggle.
In the listener, store an identifier of the toggled row. Hint: you can get the row object with event.getData()
Instead of directly accessing the data requesting component, write a proxy method in front of it which checks if the requested object belongs to the identifier stored in the listener.
Related
I am using JSF 2.2 with Primefaces 5.1. There is an editable primefaces datatable with pagination enabled.
<p:dataTable editMode="row"
editable="true"
value="#{usersBean.users}"
var="user" paginator="true" rows="20">
<p:ajax event="rowEditInit" onstart="handleRowEditInit(event,this);"/>
<p:column>
<p:rowEditor/>
</p:column>
<p:column headerText="Real name">
<p:cellEditor rendered="true">
<f:facet name="input">
<p:inputText value="#{user.realName}"/>
</f:facet>
<f:facet name="output">
<h:outputText value="#{user.realName}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="User name">
<p:cellEditor>
<f:facet name="input">
<p:inputText value="#{user.userName}"/>
</f:facet>
<f:facet name="output">
<h:outputText value="#{user.userName}"/>
</f:facet>
</p:cellEditor>
</p:column>
</p:dataTable>
Every time the page is changed the datatable does an AJAX POST with all the data of the current page. As you can partly see in the image below.
For big tables with much data this results in huge requests. This is not neccessary right? Is there a way to change this behavior?
Indeed, when you submit a form in HTML, by default every single HTML input element will be sent as request parameter. PrimeFaces ajax components therefore offer the partialSubmit="true" attribute which will then send only the HTML input elements covered by the process attribute, which defaults in <p:ajax> to #this and in <p:commandXxx> to #form.
So, just add this to the data table in case to optimize pagination performance:
<p:ajax event="page" partialSubmit="true" />
And add this to any command button which only needs to access the current row in the data table (e.g. to show it in a dialog) to optimize action processing performance:
<p:commandButton ... process="#this" partialSubmit="true" />
You can also configure it globally via below context param in web.xml:
<context-param>
<param-name>primefaces.SUBMIT</param-name>
<param-value>partial</param-value>
</context-param>
And then for cases where you actually need a full submit, explicitly use partialSubmit="false".
I'm working on dashboard application where I have to retrieve a set of records and display in dynamic tables boxes. Page frame length is fixed. now of columns and rows can be initialized. It should look like this sample:
Currently I'm using data table to display but it prints all the data in one column. How would I change my code to above pattern?
<o:dataTable id="tabBlSearch" var="item"
onkeyup="handleLeftRightArrowOnDataTable('frmDashBoard:tabBlSearch')"
value="#{bLDashBoardAction.listBondLoc}">
<o:column style="width: 20px;">
<h:outputText value="#{item.awb}" />
</o:column>
</o:dataTable>
You can achieve this with standard JSF components using a <h:panelGrid> wherein <c:forEach> is been used to generate the cells during the view build time. The <ui:repeat> won't work as that runs during view render time.
<h:panelGrid columns="5">
<c:forEach items="#{bean.items}" var="item">
<h:panelGroup>
<h:outputText value="#{item.value}" />
</h:panelGroup>
</c:forEach>
</h:panelGrid>
As to component libraries, I don't see anything in OpenFaces' showcase, but PrimeFaces has a <p:dataGrid> for exactly this purpose, even with pagination support.
<p:dataGrid columns="5" value="#{bean.items}" var="item">
<p:column>
<h:outputText value="#{item.value}" />
</p:column>
</p:dataGrid>
I am using JSF 2.2 with PrimeFaces 4.0. I have a <p:dataTable> with live scrolling, lazy loading, row-expansion and cell-editing, etc.
<p:dataTable
id="dtaTable"
selection="#{cont.selectedArray}"
resizableColumns="true"
draggableColumns="true"
var="dataModel"
value="#{cont.yieldBondsModel}"
editable="true"
editMode="cell"
selectionMode="multiple"
rowSelectMode="add"
scrollable="true"
scrollHeight="650"
rowKey="#{modeld.id}+#{model.name}"
rowIndexVar="rowIndex"
filterEvent="enter"
styleClass="screenScrollStyle"
scrollRows="25"
liveScroll="true"
lazy="true"
rows="50"
filteredValue="#{cont.filteredModel}"
widgetVar="dt4"
>
<p:rowExpansion>
<h:panelGrid id="display" columns="2" cellpadding="4" style="width:300px;" styleClass="ui-widget-content grid">
<f:facet name="header" styleClass="dataTableHeader">Other Data</f:facet>
<h:outputText value="id " />
<h:outputText value="#{dataModel.id}"/>
<h:outputText value="Name" />
<h:outputText value="#{dataModel.name}" />
</h:panelGrid>
</p:rowExpansion>
<p:column width="15">
<p:rowToggler />
</p:column>
...
</p:dataTable>
On the first page everything works like a charm. Once I scroll it down, data is getting lazy-loaded perfectly fine, but it has some problems during row-expansion and cell-editing:
In row-expansion, I am getting wrong values. Maybe overlapped values from other row.
Cell-editing is also not working. Once I edit any cell, values are not getting displayed in cell-editor. I have checked in Firebug, there is no value in <h:outputText> as confirmed by the generated HTML <div class="ui-cell-editor-output" style="display: none;"></div>. As you can see, there is no value inside the div.
The backing bean is #SessionScoped.
How is this caused and how can I solve it?
This is a known issue on PrimeFaces, and already reported and fixed in Elite version (4.0.7 if I remember well). However community release does not contain this fix yet. There is an RC for PrimeFaces 5.0 which contains this fix. You can download it and test if it's suits for you needs, but be aware that this is only a release candidate, not a final release. AFAIK the ETA for the 5.0 final is the first half of May.
This is a clumsy question!!! :)
Can this be made possible somehow? Can <p:dataTable> (whatever lazily loaded or otherwise) be updated without updating its headers (The contents (rows) inside the table along with the footer should be updated without updating the table headers)?
Updating of <p:dataTable> may be triggered by any UICommand like <p:commandButton>, <p:commandLink> and alike.
Something like this can be visualized, when we edit/update rows using <p:cellEditor> in conjunction with <p:rowEditor/> in <p:dataTable> (not sure about single cell editing).
<p:dataTable id="dataTable" var="row" value="#{bean}" ...>
<p:column headerText="Header 1" sortBy="#{row.property1}" filterBy="#{row.property1}">
....
</p:column>
<p:column>
<!--They may be our own headers-->
<f:facet name="header">
Header 2
...
</f:facet>
....
</p:column>
...
</p:dataTable>
Easiest way is to use PrimeFaces Selectors (PFS) for this. This only requires the desired cell content being wrapped in another component with an ID and a style class — so that jQuery can find and collect them.
E.g.
<p:dataTable ...>
<p:column>
<f:facet name="header">...</f:facet>
<h:panelGroup id="col1" styleClass="cell">...</h:panelGroup>
</p:column>
<p:column>
<f:facet name="header">...</f:facet>
<h:panelGroup id="col2" styleClass="cell">...</h:panelGroup>
</p:column>
<p:column>
<f:facet name="header">...</f:facet>
<h:panelGroup id="col3" styleClass="cell">...</h:panelGroup>
</p:column>
...
</p:dataTable>
<p:commandButton value="update" update="#(.cell)" />
That wrapping is clumsy, yes, but that's best you can get without homebrewing a custom renderer. You can always create a <my:column> tagfile to reduce the boilerplate.
See also:
How do PrimeFaces Selectors as in update="#(.myClass)" work?
I am using JSF 2.0 with Primefaces. I have a page with a data table containing a list of users in the system. Each user can have a collection of roles, so i would like to have a button to select a bunch of roles. I wanted this to be an ajax selector and reusable from other pages, so this is how i have laid it out.
User List page
<h:form prependId="false">
<p:dataTable id="userList" var="user" value="#{userBean.users}">
<p:column id="modelHeader">
<f:facet name="header">
Name
</f:facet>
<h:outputText value="#{user.name}" />
</p:column>
<p:column>
<f:facet name="header">
Select Roles
</f:facet>
<p:commandButton id="selectButton" oncomplete="roleDialog.show()" icon="ui-icon-search" title="Select Roles" />
</p:column>
</p:dataTable>
</h:form>
Dialog defined inside user list page, but the contents will be moved to an include to promote reusability
<p:dialog header="Roles" widgetVar="roleDialog" resizable="true" id="roleDialog" modal="true">
<h:form prependId="false">
<h:panelGrid id="display" columns="2" cellpadding="4" style="margin:0 auto;">
<p:dataTable id="roleList" var="user" value="#{roleBean.roles}">
<p:column id="modelHeader">
<f:facet name="header">
Name
</f:facet>
<h:outputText value="#{role.name}" />
</p:column>
<p:commandButton id="selectButton" actionListener="#{roleBean.selectRoles}" title="Select Roles" />
</h:panelGrid>
</h:form>
</p:dialog>
My question is, I am not sure how to achieve the following.
I would like to pass arguments to the role selector as criteria before rendering the content in the dialog.I can do this via f:setPropertyActionListener.. correct?
After the role is selected, i would like to pass the selected id back to the user list page. I can do this via addCallbackParam, correct?
Then i would like to pass that value back into the userList bean to an action listener to associate this role(s) to the user
What is the best pattern to achieve this workflow in JSF. I do not want to duplicate my role selector in each page as i would like to re-use that.
Thank you for your patience in reading through this long post. I appreciate your response and
suggestions.
The best pattern for this would be to implement a composite component.