Our project recently upgraded from primefaces v4.0.24 to primefaces v5.1.6.
Upon testing there it was found that when the datatable is printed to printer or PDF there were formatting issues. The column headers were not correctly justified especially the one having longer values.
However it fits correctly if I change the layout to landscape.
I want the data to be correctly justified in portrait mode.
This wasn't the problem with previous version of primefaces.
The page consists of commandlink and datatable.
When the user clicks on commandlink the id of the datatable is passed to p:printer.
Here is the code
<h:commandLink styleClass="ui-icon-export-print" title="#{webmsg['action.export.print.hint']}">
<p:printer target="companyTable" />
</h:commandLink>
<p:dataTable id="companyTable" widgetVar="companyTable" var="company" value="#{companies}"
sortBy="#{company.shortName}" sortOrder="ascending" filterEvent="enter"
filteredValue="#{companyForm.filteredCompanies}">
<f:facet name="header">
<h:outputText value="#{appmsg['label.companies']}" />
</f:facet>
<p:column sortBy="#{company.shortName}" filterBy="#{company.shortName}" filterMatchMode="contains" >
<f:facet name="header">
<h:outputText value="..." />
</f:facet>
<h:outputText value="#{company.shortName}" />
</p:column>
.....
</p:dataTable>
The data is either cuttoff or it touches the column border.
If I go to print options and change the default size of paper from A4 to Tabloid, then the data correctly fits within the column.
There should be some way to autofit the data with the default paper size.
Any ideas or clues to fix the formatting issue would be appreciated. Thanks.
Yes, you can use css for this. It has media types so you can tune things for just print devices and leave the screen things untouched. You can also change the ['paper size']there
Related
I'm trying to make a datatable showing column as easy as possible - like auto width.
It misaligns the columns compared to the header, like these:
My code looks like this:
<p:dataTable id="datalist2" value="#{item.formItemCollection}"
var="item2" scrollable="true" scrollHeight="100" tableStyle="width:auto"
emptyMessage="#{bundle.EmptyMessage}" >
<ui:include src="/view/formItem/formItemListRow.xhtml">
<ui:param name="rowItem" value="#{item2}"/>
<ui:param name="controller" value="#{formItemController}"/>
</ui:include>
I have a table which I want to hide particular column as below.
For example, I want to hide 3 last columns under the tag <p:columns> </p:columns>
<p:dataTable id="dynaDataTable" var="row" value="#{onListBean.rowList}" style="font-size:12px;"
selectionMode="single" selection="#{onListBean.selectedRow}" rowKey="#{row.s_nr}"
widgetVar="dynaTable" emptyMessage="Empty!" rowIndexVar="rowIndex"
scrollable="true" scrollHeight="100%">
<p:column id="rowNumber" exportable="false" headerText="#" style="max-width:50px; width:20px" >
<h:outputText value="#{rowIndex+1}" />
</p:column>
<p:columns headerText="#{column.header}" value="#{onListBean.columns}" var="column" >
<div style="text-align: center;">
<h:outputText value="#{row[column.property]}"/>
</div>
</p:columns> </p:dataTable>
Any Idea?
Just create a method in your bean which will return the columns you want to display, and use that with <p:columns value="...". If that is somehow not possible, you can also use the visible attribute, for example visible="#{column.header ne 'excludeMe'}".
If you are looking to display columns based on the available screen width, you should have a look at either the responsivePriority property, or <p:dataTable reflow="true".
See also:
https://www.primefaces.org/showcase/ui/data/datatable/responsive.xhtml
I couldn't understand from your question if you need it done using a UI component or not. If yes, Primefaces has a pretty nice component <p:columnToggler /> which lets you hide and show the table columns whenever you want.
If you were talking about the other scenario, I still think you could do some trick with columntoggler while not displaying it in the UI.
The Primefaces Documentation states that the following code will be invalid due to the fact that every layoutUnit needs its own form:
<p:layout fullPage="true">
<h:form>
<p:layoutUnit position="north">
<p:inputText value="#{testBean.input1}" />
</p:layoutUnit>
<p:layoutUnit position="center">
<p:inputText value="#{testBean.input2}" />
<p:commandButton value="save" action="#{testBean.save}" />
</p:layoutUnit>
<p:layoutUnit position="south">
<p:inputText value="#{testBean.input3}" />
</p:layoutUnit>
</h:form>
</p:layout>
However, when I nest p:layout inside of a form, the code works without any problem:
<h:form>
<p:layout fullPage="true">
<p:layoutUnit position="north">
<p:inputText value="#{testBean.input1}" />
</p:layoutUnit>
<p:layoutUnit position="center">
<p:inputText value="#{testBean.input2}" />
<p:commandButton value="save" action="#{testBean.save}" />
</p:layoutUnit>
<p:layoutUnit position="south">
<p:inputText value="#{testBean.input3}" />
</p:layoutUnit>
</p:layout>
</h:form>
What is the explanation for that behaviour? Can my approach of having just a single form tag outside of p:layout cause problems at some time point?
The PrimeFaces documentation does indeed state on Page 309 of the 6.1 documentation
When working with forms and full page layout, avoid using a form that contains layoutunits as generated dom may not be the same. So following is
invalid.
And in that they reference your first example. It is technically not invalid but due to the way the layout component renders the html needed in the browser (and maybe client-side does dom manipulation) to get the good full page experience, it might (will? never tried it myself) result in unexpected behaviour.
They also state
A layout unit must have it’s own form instead, also avoid trying to update layout units because of same reason, update it’s content instead.
'Must have' (emphasis above is mine) is to strong here, they'd better have stated
give each layout unit its own form if a form is needed in the layout unit.
A full form around the full page layout might work now assuming the layout will not mess with things and e.g. add parts to the surrounding body tag (if it does do dom manipulation to achieve a certain behaviour), but I doubt they'd give you guarantees. An additional reason to not do it like you ask might be that you can run into nested forms when developers of 'partial pages' a not fully aware of the 'god form'. So I would advise against it.
So if e.g. the north and south layoutunit contain sort of fixed functionality (header with search, footer with some features) then put a h:form directly in the layout unit. If the center part contains dynamic things e.g. a ui:include, put the `h:form in the included parts.
See also:
How to use <h:form> in JSF page? Single form? Multiple forms? Nested forms?
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
I have a panelGrid with a row containing a selectCheckBoxMenu and another row which should be shown or hidden based on the selection.
Updating the entire panel when the selection is changed is not desired, because the selectCheckBoxMenu would be refreshed and the user would have to open the dropdown again for each item he wants to select.
Updating the controls to be hidden or shown can't solve the problem either because they can't be updated if they are not shown because rendered was false before.
So, I wrapped these controls in a Fragment and update those fragments. Functionally that's OK, but now I have an ugly layout because in most situations the controls will be hidden and a small empty row is shown.
Is it possible to get rid of that ugly empty row without breaking the functionality again?
My xhtml looks like this:
<p:panelGrid id="panel" columns="2" border="0" cellpadding="5"
cellspacing="2">
...
<h:outputLabel value="Type" />
<p:selectCheckboxMenu id="deviceTypeMenu" value="#{controller.criteria.dts}" label="All" converter="dtConverter"
filter="true" filterMatchMode="contains"
panelStyle="width:300px" valueChangeListener="#{controller.onChange}"
updateLabel="true">
<p:ajax update="sclabel scfield" />
<f:selectItems value="#{deviceTypeBean.alldts}" var="dt"
itemLabel="#{dt.name}" itemValue="#{dt}"/>
</p:selectCheckboxMenu>
...
<p:fragment id="sclabel">
<h:outputText value="Detail" rendered="#{controller.detailRequired}"/>
</p:fragment>
<p:fragment id="scfield">
<p:selectCheckboxMenu rendered="#{controller.detailRequired}" converter="#{detailConverter}"
value="#{controller.criteria.detail}" label="All details"
filter="true" filterMatchMode="contains"
style="width:300px;" scrollHeight="100"
updateLabel="true">
<f:selectItems value="#{detailConverter.values}" var="adetail"
itemLabel="#{adetail.name}" itemValue="#{adetail}" />
</p:selectCheckboxMenu>
</p:fragment>
...
</p:panelGrid>
Cause
The empty row contains padding. The table row and table cell html elements are created by the panelgrid because it renders those for every row and as soon as there some child element a row is rendered. And they have styleclasses on them which are set by the panelgrid and refer to styles which contain padding. The fragments, even if they don't render anything themselves are enough to trigger that.
Remark: We are using the Modena theme from Primefaces. So, the padding is part of the Modena theme.
Extract of the Modena stylesheet which causes the problem:
.ui-panelgrid .ui-panelgrid-cell {
border-width: 1px;
border-style: solid;
border-color: inherit;
padding: 4px 10px;
}
Solution
I did the following changes:
I explicitly specified rows and columns using primefaces row and column components and added a style class "ui-panelgrid-cell-nopadding" to the columns of the row which I need to hide. I added the style below to my stylesheet so that, that style class removes/overrides padding from that cell which was added by the panelgrid.
.ui-panelgrid .ui-panelgrid-cell-nopadding {
padding: 0px 0px;
}
I added a div around the controls in the cells and applied the class ui-panelgrid-cell to it to add the padding which I removed from the cells.
Remark: I tried a panel first for this, but then it became more complicated because the Primefaces panel also adds styleclasses which caused inconsistent layout with the other rows in my panelgrid (fontsize was changed).
I added a second fragment between the fragments I already had and the div's and I moved the rendered attribute from the controls inside the cells to these fragments. So that the padding defined on the div is no longer there if I don't want the row to be rendered.
One fragment is not enough anymore, because I needed one with an id to be able to update it via ajax and a second with the rendered attribute. If you put those attributes on the same fragment, you can't make it visible anymore as soon as it's hidden. Moving the id's to the explicitly defined columns is also not possible because then these cells behave strangely probably because they are empty when rendering the panelgrid initially. When the cells were updated to make them visible, the content of both the cells of my row appeared in the left cell and the right cell remained empty.
After that, I had a border around the div's because that is specified in the Modena style which I applied to the div's to have the padding that I removed from the cells. And because the content of the div's was smaller than the cell, I had an extra border, I didn't want. So I added something to my stylesheet to remove that border.
.ui-panelgrid .ui-panelgrid-cell-nopadding .ui-panelgrid-cell {
border:none; border:0px;
}
My xhtml now looks like this:
<p:panelGrid id="panel" border="0">
...
<p:row>
<p:column>
<h:outputLabel value="Type" />
<p:selectCheckboxMenu id="deviceTypeMenu" value="#{controller.criteria.dts}" label="All" converter="dtConverter"
</p:column>
<p:column>
filter="true" filterMatchMode="contains"
panelStyle="width:300px" valueChangeListener="#{controller.onChange}"
updateLabel="true">
<p:ajax update="sclabel scfield" />
<f:selectItems value="#{deviceTypeBean.alldts}" var="dt"
itemLabel="#{dt.name}" itemValue="#{dt}"/>
</p:selectCheckboxMenu>
</p:column>
</p:row>
...
<p:row>
<p:column styleClass="ui-panelgrid-cell-nopadding">
<p:fragment id="sclabel">
<p:fragment rendered="#{controller.detailRequired}">
<div class="ui-panelgrid-cell">
<h:outputText value="Detail"/>
</div>
</p:fragment>
</p:fragment>
</p:column>
<p:column styleClass="ui-panelgrid-cell-nopadding">
<p:fragment id="scfield">
<p:fragment rendered="#{controller.detailRequired}">
<div class="ui-panelgrid-cell">
<p:selectCheckboxMenu converter="#{detailConverter}"
value="#{controller.criteria.detail}" label="All details"
filter="true" filterMatchMode="contains"
style="width:300px;" scrollHeight="100"
updateLabel="true">
<f:selectItems value="#{detailConverter.values}" var="adetail"
itemLabel="#{adetail.name}" itemValue="#{adetail}" />
</p:selectCheckboxMenu>
</div>
</p:fragment>
</p:fragment>
</p:column>
<.p:row>
...
</p:panelGrid>
For example put an Id to row:
in javascript :
if (condition that you need)
{
document.getElementById("form:idEmpresa").style.display = "none";
}
Ready
My goal is to produce a table with two header rows. The first with a few column-spanning cells, the second with all 1-cell headers, but with sortBy and filterBy enabled.
<p:dataTable .... >
<p:columnGroup type="header">
<p:row>
<p:column colspan="3" headerText="my header 1" />
<p:column colspan="3" headerText="my header 2" />
</p:row>
</p:columnGroup>
<p:column sortBy="#{myBean.var1}" filterBy="#{myBean.var1}" headerText="var1">
<h:outputText value="#{...var1}" />
</p:column>
.
.
</p:dataTable>
I can get either the columnGroup to show up or the per-column headerText with sortBy and filterBy, but not both. When I mix them, the header components from the per-column header row disappears.
As it turns out, it is possible to nest dataTables via the subTable component. This showcase example demonstrates nesting a subTable in a larger dataTable, there-by achieving filtering and sorting combined with columnGroups in the headers.