Primefaces ExcelExporter with CommandLinks - jsf

I have an application that contains commandLinks within a Primefaces dataTable. The commandLinks link to other pages within the application and pass parameters. When I try to export the dataTable using Primefaces' ExcelExporter, the generated .xls file contains the value attribute for the commandLink, not the value attribute for the outputText nested within the commandLink.
Column within dataTable code:
<p:dataTable var="dataRow" id="myTable">
<p:column>
<f:facet name="header">
<h:outputText value="MyColumn" />
</f:facet>
<h:outputLink value="myPage.xhtml">
<f:param name="columnId" value="#{dataRow.columnId}" />
<h:outputText value="#{dataRow.columnName }" />
</h:outputLink>
</p:column>
</p:dataTable>
ExcelExporter code:
<h:commandLink>
<h:outputText value="Export" />
<p:dataExporter type="xls" target="myTable" fileName="tableResults"/>
</h:commandLink>
When I export the table using the ExcelExporter, the exported data is "myPage.xhtml", when I want it to be the data contained in "#{dataRow.columnId}". Is there a way to format the links so they are exported with the text that I want?

I was able to solve this problem by changing the links to commandLinks with actions that determine navigation and setPropertyActionListeners to pass parameters. It looks like PrimeFaces always takes the value from the parent component, so this seemed to be the best workaround. The dataExporter code stayed the same.
Modified xhtml code:
<p:dataTable var="dataRow" id="myTable">
<p:column>
<f:facet name="header">
<h:outputText value="MyColumn" />
</f:facet>
<h:commandLink value="#{dataRow.columnName}" action="myPage">
<f:setPropertyActionListener target="#{myPage.columnId}"
value="#{dataRow.columnId}"/>
</h:commandLink>
</p:column>
</p:dataTable>
Navigation rule added to faces-config.xml:
<navigation-rule>
<navigation-case>
<from-outcome>myPage</from-outcome>
<to-view-id>/myPage.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>

Related

Primefaces datatable update datatable

I have a problem with primefaces datatables. I have one datatable with some entries and a column with a button inside. If the button is pressed a popup is opened with another datatable. The entries in the second datatable are depending on the row in which the button is pressed.
<!-- first datatable -->
<h:form id="list">
<p:dataTable id="list1" var="item" value="#{bean1.itemlist}"
rowKey="#{item.id}" selection="#{bean1.selectedItem}"
selectionMode="single">
<p:column headerText="ID">
<h:outputText value="#{item.id}" />
</p:column>
...
<p:column headerText="Edit Entries">
<p:commandButton value="Edit Entries"
actionListener="#{bean2.updateEntries(item)}" ajax="true"
oncomplete="PF('edit_entries').show()" />
</p:column>
</p:dataTable>
<!-- Second datatable in the popup -->
<p:dialog header="Edit Entries" widgetVar="edit_entries" modal="true"
resizable="false">
<p:dataTable id="list2" var="entry"
value="#{bean2.entriesList}" rowKey="#{entry.id}"
selection="#{bean2.selectedEntry}" selectionMode="single">
<p:column headerText="Entry Number">
<h:outputText value="#{entry.number}" />
</p:column>
</p:dataTable>
<f:facet name="footer">
<p:commandButton value="Save" oncomplete="PF('edit_entries').hide()" />
</f:facet>
</p:dialog>
</form>
Bean2
public void updateEntries(Item selectedItem) {
this.entriesList = this.entriesQuery.getAllEntriesByItemID(selectedItem.getId());//db query could take some time
System.out.println("entrieslist size: " + this.entriesList.size()); //prints the correct size
}
The problem is that there are no entries listed in the popup datatable although there are some in the list after the db query.
Any ideas how to fix this bug?
Thanks in advance!
UPDATE 1:
<!-- first datatable -->
<h:form id="list">
<p:dataTable id="list1" var="item" value="#{bean1.itemlist}"
rowKey="#{item.id}" selection="#{bean1.selectedItem}"
selectionMode="single">
<p:column headerText="ID">
<h:outputText value="#{item.id}" />
</p:column>
...
<p:column headerText="Edit Entries">
<p:commandButton value="Edit Entries" update=":dialogUpdateEntries"
actionListener="#{bean2.updateEntries(item)}" ajax="true"
oncomplete="PF('edit_entries').show()" />
</p:column>
</p:dataTable>
</h:form>
<!-- Second datatable in the popup -->
<p:dialog header="Edit Enries" id="dialogUpdateEntries" widgetVar="edit_entries" modal="true"
resizable="false">
<h:form id="formEntriesList">
<p:dataTable id="list2" var="entry"
value="#{bean2.entriesList}" rowKey="#{entry.id}"
selection="#{bean2.selectedEntry}" selectionMode="single">
<p:column headerText="Entry Number">
<h:outputText value="#{entry.number}" />
</p:column>
</p:dataTable>
<f:facet name="footer">
<p:commandButton value="Save" oncomplete="PF('edit_entries').hide()" />
</f:facet>
</form>
</p:dialog>
You're indeed not updating the data table in the dialog. JSF doesn't automatically update the view on change of the model, you have to explicitly tell the view to do so. You can use the ajax action component's update attribute for this. This takes a JSF client ID which can be found by rules as outlined in this related answer: How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar".
Given the markup as shown in the question, that'll be
<p:commandButton ... update=":list:list2" />
However, there's another potential problem. You're using <p:dialog modal="true"> inside a form instead of giving the dialog its own form. This way the dialog may not be available in the HTML DOM tree as JavaScript (the one responsible for dealing with ajax stuff) would expect to find it. Giving the dialog its own form should fix this matter. It'll also fix the potential future problems with invoking actions from inside the dialog as handled in this related question: <p:commandbutton> action doesn't work inside <p:dialog>.
<h:form id="viewForm">
...
<p:commandButton ... update=":editDialog" />
...
</h:form>
<p:dialog id="editDialog" modal="true">
<h:form id="editForm">
...
</h:form>
</p:dialog>
Try adding update="list2" to Edit Entries command button (even update="#widgetVar(edit_entries)" should work).
If, because of page layout and structure, you can't target the second datatable using above suggestions, then add styleClass="tList2" to second table, and update it with update="#(.tList2)" on edit button.

p:dataTable (row selection) selection and pe:inputNumber not working

I have a <p:dataTable > which is updated from a button and is also filled. The data is displayed correctly. But the PROBLEM is that when I click/select any row, NO RESPONSE; previously while being clicked, the row was highlighted, now-> no highlight. I have done this type of design many times but this time the <p:dataTable> is behaving weirdly. I cannot find the root of problem.
My XHTML snippet for table is :
<p:dataTable id="tblSales" rowIndexVar="rowsn"
paginator="true" value="#{invSaleMB.dummyList}"
var="saleObj" selectionMode="single"
selection="#{invSaleMB.dummySaleObj}"
rowKey="#{saleObj.item.itemTypeId}">
<p:column headerText="#">
<h:outputLabel value="#{rowsn+1}" />
</p:column>
<p:column headerText="Name">
<h:outputLabel value="#{saleObj.item.itemTypeName}" />
</p:column>
<p:column headerText="Count">
<h:outputLabel value="#{saleObj.count}" />
</p:column>
<p:column headerText="Unit Price">
<h:outputLabel value="#{saleObj.unitPrice}" />
</p:column>
<p:column headerText="Total Price">
<h:outputLabel value="#{saleObj.total}" />
</p:column>
</p:dataTable>
My backing bean is #ViewScoped.
And another component which is not responding to an update trigger is <pe:inputNumber> and value for this component is 'double'. I changed the <pe:inputNumber> to <p:inputText> and worked well and displayed accurate data.
<pe:inputNumber id="totalCost" disabled="true" value="#{invSaleMB.totCost}" />
The datatable and pe:inputNumber are on same form.
What have you changed between "before" (was working) and "now" (not working)?. You are sure "#{saleObj.item.itemTypeId}" is unique for each element of the table? More code of the page could be useful.
For pe:inputNumber to work remember to include xmlns:pe="http://primefaces.org/ui/extensions" in your html tag.

Primefaces - Cannot find component with identifier outside the datatable

<ui:define name="content">
<f:view>
<h:form id="myForm" styleClass="form" >
<p:dataTable var="provider" id="ss" value="#{providerSelectBean.providerList}" rowKey="#{provider.license}"
selection="#{providerSelectBean.selectedProvider}" selectionMode="single">
<p:ajax listener="#{providerSelectBean.onRowSelect}"
update=":myForm:output"event="rowSelect"/>
<p:column sortBy="#{provider.license}" width="110" >
<f:facet name="header">
<h:outputText value="License#" />
</f:facet>
<h:outputText value="#{provider.license}" />
</p:column>
<p:column sortBy="#{provider.prgName}" width="110" >
<f:facet name="header">
<h:outputText value="Program Name" />
</f:facet>
<h:outputText value="#{provider.prgName}" />
</p:column>
</p:dataTable><br/>
<p:panelGrid id="output" >
<h:outputText value="License" />
<h:outputText value="#{provider.license}" />
</p:panelGrid>
</h:form>
</f:view>
</ui:define>
This is my first stint with JSF2.0 and primefaces 3.4.1 and the <p:ajax update gives an error
javax.faces.FacesException: Cannot find component with identifier
":myForm:output" referenced from "myForm:ss"
Try to inspect the generated HTML code and see the actual id being generated for your panelGrid and update that id. If it happens to be dynamic, you can always use the JQuery CSS selectors (I find myself doing that pretty often). In your case, you can go like this:
update="#([id$=output])"
This expression stands for every component whose id ends with output. Take a look at the JQuery docs for more info.
You can also use :#{p:component(componentId)} as in
<p:ajax listener="#{providerSelectBean.onRowSelect}"
update=":#{p:component('output')}" event="rowSelect"/>
Quoting BalusC's answer to Get id of parent naming container in template for in render / update attribute:
p:component is a helper function that scans the entire view root for a component with the given ID and then returns its client ID.

Primefaces DataTable ajax not updating any component except itself

<h:form id="form">
<p:messages />
<p:panel header="Análise">
<h:outputText value="Mês da análise: " />
<p:selectOneMenu value="#{report005.selectedMes}">
<f:selectItems var="data" value="#{report005.analiseMeses}" itemLabel="#{report005.formataDataCombo(data)}" />
<f:convertDateTime pattern="MM/yyyy" />
</p:selectOneMenu>
<p:commandButton value="Análises" update="analiseTable" actionListener="#{report005.loadAnalise()}" />
<p:dataTable id="analiseTable" var="pes" value="#{report005.analiseModel}" selection="#{report005.selectedAnalise}" emptyMessage="Não há registros...">
<p:column selectionMode="multiple" style="width:18px" />
<p:ajax event="rowSelectCheckbox" listener="#{report005.loadAnaliseProduto()}" update="produtosmanycheck" />
<p:column headerText="Código">
#{pes.cod_analise}
</p:column>
<p:column headerText="Nome">
#{pes.dsc_analise}
</p:column>
<p:column headerText="Descrição">
#{pes.dsc_resumida_acao}
</p:column>
<p:column headerText="Planejamento">
<h:outputText value="#{pes.dat_planejamento_analise}">
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:outputText>
</p:column>
</p:dataTable>
</p:panel>
<p:panel header="Produto Gerencial">
<p:selectManyCheckbox id="produtosmanycheck" value="#{report005.selectedProduto}" layout="pageDirection">
<f:selectItems id="teste" value="#{report005.produtos}" />
</p:selectManyCheckbox>
</p:panel>
<p:commandButton value="Enviar" action="#{report005.send}" ajax="false" />
</h:form>
Whan the AJAX event "rowSelectCheckbox" is fired, it does not find the 'produtosmanycheck' component to update, returning the following error to me:
javax.faces.FacesException: Cannot find component with identifier
"produtosmanycheck" referenced from "form:analiseTable". at
org.primefaces.util.ComponentUtils.findClientIds(ComponentUtils.java:251)
at
org.primefaces.util.AjaxRequestBuilder.addIds(AjaxRequestBuilder.java:102)
at
org.primefaces.util.AjaxRequestBuilder.update(AjaxRequestBuilder.java:90)
I already tried= :form:produtosmanycheck, form:produtosmanycheck, :produtosmanycheck, produtosmanycheck
I tried removing the FORM id too... without success...
What am I doing wrong? I can't update any component but the DataTable...
You can reach that produtosmanycheck using :form:produtosmanycheck
EDIT: Nested forms will not work properly and give all kinds of DOM issues like the one you're experiencing. Work out a way to separate your view components into separate forms and then try the above named access.
Have you tried putting the id "produtosmanycheck" on the parent p:panel element instead of on the p:selectManyCheckbox itself?
Form nesting should never be done in JSF even with prepend ID false as it will cause unexpected or no behaviour.
I will post my own answer (in the end I came up with nested forms idea) as well as voting up #kolossus because he was basically right and couldn't know about nested forms.
Nested forms aren't the "thing" of JSF only (as it may seem from #JordanDenison answer), it is a general rule of HTML --> nesting forms is forbidden in HTML !
You may want to read this nesting forms in HTML

JSF render is not working for form element

I have a composite displayed inside a dialog. I have an edit button that get the current bean #SessionScoped (item in a data table) and then update the UI. My app is very similar to a simple CRUD app like http://balusc.blogspot.com/2010/06/benefits-and-pitfalls-of-viewscoped.html.
The problem is that the UI is updated correctly when using <h:outputText/> but not when using a form element.
<h:inputTextarea value="#{cc.attrs.managedBean.assertionStatement}" />
<h:inputText value="#{cc.attrs.managedBean.assertionStatement}" />
<h:outputText value="#{cc.attrs.managedBean.assertionStatement}"/>
The UI shows an empty textarea and input but the outputText renders the correct value. The getAssertionStatement() is called 3 times which seems to be the correct behavior.
When I close the dialog and reopen it, everything (form element) is populated.
The dialog call (ag namespace is for composite component):
<p:dialog widgetVar="DataValueRuleDialog" modal="true" height="600" width="800">
<p:outputPanel id="DataValueRulePanel">
<ag:DataValueAssertion managedBean="#{dataValueAssertionController}" id="DataValueComposite" />
</p:outputPanel>
</p:dialog>
The composite that calls another composite:
<h:form id="DataValueForm">
<ag:assertionMetadataComponent
managedBean="#{cc.attrs.managedBean.dataValueAssertionBean.assertionMetadataBean}"
assertionStatementRows="5" />
<p:dataTable value="#{cc.attrs.managedBean.model}" var="item">
<p:column>
<f:facet name="header">Assertion Statement</f:facet>
<h:outputText rendered="#{item.profileBean.profileLocation == cc.attrs.managedBean.selectedComformanceProfile.name}" value="#{item.assertionMetadataBean.assertionStatement}" />
</p:column>
<p:column>
<p:commandButton rendered="#{item.profileBean.profileLocation == cc.attrs.managedBean.selectedComformanceProfile.name}" value="edit" immediate="true"
actionListener="#{cc.attrs.managedBean.editDataValueAssertion}" update=":DataValueComposite:DataValueForm">
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
When I remove the immediate=true the form is validated and since one of the required field (supposed to be populated) is missing, I got a validation error. This is why I have immediate=true but it should be necessary since all the items in the data table should be valid.

Resources