Primefaces DataTable ajax not updating any component except itself - jsf

<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

Related

How to update a field using a converter and ajax in JSF

I basically have two input field I display if the value is currently empty or null. if it is not, I display an outputText. Those two values are currency values stored in a Long object and I use a converter to display the data properly (I can't use PrimeFaces' inputNumber since I am using PrimeFaces 5.3). My problem is the following :
<c:set var="edtVal1" value="#{bean.val1 ne null and bean.val1 ne 0}" scope="request" />
<c:set var="edtVal2" value="#{bean.val2 ne null and bean.val2 ne 0}" scope="request" />
<p:panelGrid>
<p:row>
<p:column colspan="2">
<p:messages id="mainMessages" globalOnly="false" autoUpdate="true" showDetail="true" />
</p:column>
</p:row>
<!-- [...] -->
<p:row>
<p:column styleClass="col-quarter col-label2">
<h:outputText value="value 1" />
</p:column>
<p:column styleClass="col-quarter col-value2" rendered="#{edtVal1}">
<h:outputText id="val1Output" value="#{bean.val1}" converter="myConverter" />
</p:column>
<p:column styleClass="col-quarter" rendered="#{not edtVal1}">
<p:inputText id="val1Input" value="#{bean.val1}" converter="myConverter">
<p:ajax update="mainMessages val1Input" event="change" />
</p:inputText>
</p:column>
</p:row>
<p:row>
<p:column styleClass="col-quarter col-label2">
<h:outputText value="value 2" />
</p:column>
<p:column styleClass="col-quarter col-value2" rendered="#{edtVal2}">
<h:outputText id="val1Output" value="#{bean.val2}" converter="myConverter" />
</p:column>
<p:column styleClass="col-quarter" rendered="#{not edtVal2}">
<p:inputText id="val1Input" value="#{bean.val2}" converter="myConverter">
<p:ajax update="mainMessages val1Input" event="change" />
</p:inputText>
</p:column>
</p:row>
</p:panelGrid>
when I put it like this, the messages thrown by the converter are displayed, but none of the fields are updated. However, if I use the same boolean variable for both input/output options (changed the variable used in rendered attribute of the 1rst data row to use edtVal2 in both) like so :
<p:row>
<p:column styleClass="col-quarter col-label2">
<h:outputText value="value 1" />
</p:column>
<p:column styleClass="col-quarter col-value2" rendered="#{edtVal1}">
<h:outputText id="val1Output" value="#{bean.val1}" converter="myConverter" />
</p:column>
<p:column styleClass="col-quarter" rendered="#{not edtVal1}">
<p:inputText id="val1Input" value="#{bean.val1}" converter="myConverter">
<p:ajax update="mainMessages val1Input" event="change" />
</p:inputText>
</p:column>
</p:row>
The first field updates successfully and the second once still does not work.
Using a converter to display a formated data is a workaround I already done and it works just as expected and I use the same converter than before. But this time, I don't understand why it's not working.
The converter is important to reproduce the issue, but any custom converter seems to do the job.
Any other solutions are still welcome on this post, but I managed to find a working solution :
when I changed the rendered attribute to a constant string, the issue was absent. So I think the problem comes from a misunderstanding of <c:set>.
My solution was to use a the bean as a controller. I changed the variables from the xhtml file to properties in the controller and now everything works fine. So I removed all <c:set> from my xhtml and use a proper MVC pattern on that page now.
Note :
For those who don't know what MVC is : it's a neat architectural pattern that divides clearly the user interface and manipulated data. Learn more on wikipedia.

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.

Blocking a child/enclosing component of iterating components like p:dataTable using p:blockUI or pe:blockUI does not work

I'm targeting a <p:dataTable> to be blocked by <pe:blockUI> as follows.
<pe:blockUI target="dataTable" widgetVar="blockUIWidget">
<h:outputText value="Sending data..."/>
</pe:blockUI>
<p:dataTable id="dataTable" var="row" value="Test">
<p:column>
<p:commandLink id="link" value="Link" onstart="PF('blockUIWidget').block()" oncomplete="PF('blockUIWidget').unblock()"/>
</p:column>
</p:dataTable>
Naturally, this functions well.
I need not target the entire data table but only the link inside the table. The following attempt to do so is unsuccessful.
<pe:blockUI target="dataTable:link" widgetVar="blockUIWidget">
<h:outputText value="Sending data..."/>
</pe:blockUI>
Here, the value of the target attribute has been changed from dataTable to dataTable:link to make it refer to the link (the data table remains stationary).
In this case, it remains mute. Neither errors on the browser console nor any exceptions occur.
The same thing happens with <p:blockUI>. The following attempt functions well as it is meant for.
<p:blockUI block="dataTable" widgetVar="blockUI"/>
<p:dataTable id="dataTable" var="row" value="Test">
<p:column>
<p:commandLink id="link" value="Link" onstart="PF('blockUI').show()" oncomplete="PF('blockUI').hide()"/>
</p:column>
</p:dataTable>
Making <p:blockUI> point to the <p:commandLink> inside the table as follows however, does not function.
<p:blockUI block="dataTable:link" widgetVar="blockUI"/>
Again no errors, no exceptions.
What is the point? Can enclosing components of iterating components not be targeted by <p:blockUI> or <pe:blockUI>?
This works well, when a <p/pe:blockUI> is defined inside data table column/s themselves as follows.
<p:dataTable id="dataTable" var="row" value="Test">
<p:column>
<!--Using PrimeFaces Extensions <pe:blockUI>-->
<pe:blockUI target="link" widgetVar="blockUIWidget">
<h:outputText value="Sending data..."/>
</pe:blockUI>
<p:commandLink id="link" value="Link" onstart="PF('blockUIWidget').block()" oncomplete="PF('blockUIWidget').unblock()"/>
</p:column>
<p:column>
<!--Using PrimeFaces <p:blockUI>-->
<p:blockUI block="link1" widgetVar="blockLink1UI" />
<p:commandLink id="link1" value="Link1" onstart="PF('blockLink1UI').show()" oncomplete="PF('blockLink1UI').hide()"/>
</p:column>
<p:column>
<!--Using PrimeFaces <p:blockUI>-->
<p:blockUI block="link2" widgetVar="blockLink2UI" />
<p:commandLink id="link2" value="Link2" onstart="PF('blockLink2UI').show()" oncomplete="PF('blockLink2UI').hide()"/>
</p:column>
</p:dataTable>

How to set selected item in bean in <p:dataList>

I am using p:dataList because I am developing a PrimeFaces mobile view displaying a list of items. When clicking on any item, another pm:view of the same view should be displayed. But the bean should be notified of the selected item.
Unfortunately I couldn't find a way to update the bean successfully: <p:ajax> inside dataTable throws this exception:
<p:ajax> Unable to attach <p:ajax> to non-ClientBehaviorHolder parent
Using <f:setPropertyActionListener> inside the iterative element fails too because I get:
<f:setPropertyActionListener> Parent is not of type ActionSource
This is my code:
<pm:view id="instrumentsView" >
<pm:content >
<h:form id="instrumentsList" >
<p:dataList var="instrument" value="#{instrumentBean.subscribedInstruments}" >
<h:outputLink value="#newView" >#{instrument.longName}</h:outputLink>
<f:setPropertyActionListener value="#{instrument}" target="#{instrumentBean.selectedInstrument}" />
</p:dataList>
</h:form>
</pm:content>
</pm:view>
Clearly, I am using dataList and outputLink because as far as I understand, they are the components optimized for the use in PrimeFaces mobile lists. But I am available to find other options if necessary.
I found out in the showcase (example titled News) the correct way of handling the problem:
<p:dataList var="instrument" value="#{instrumentBean.subscribedInstruments}" >
<p:column >
<p:commandLink value="#{instrument.longName}" action="pm:newView" update=":compId">
<f:setPropertyActionListener value="#{instrument}" target="#{instrumentBean.selectedInstrument}" />
</p:commandLink>
</p:column>
</p:dataList>
There is a topic explaining this in the primefaces documentation.
Selecting Data (page 124)
indexed_primefaces_users_guide_3_5.pdf
http://www.primefaces.org/documentation.html
Here is the content
<h:form id="carForm">
<p:dataGrid var="car" value="#{carBean.cars}" columns="3" rows="12">
<p:panel header="#{car.model}">
<p:commandLink update=":carForm:display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{car}"
target="#{carBean.selectedCar}"
<h:outputText value="#{car.model}" />
</p:commandLink>
</p:panel>
</p:dataGrid>
<p:dialog modal="true" widgetVar="dlg">
<h:panelGrid id="display" columns="2">
<f:facet name="header">
<p:graphicImage value="/images/cars/#{car.manufacturer}.jpg" />
</f:facet>
<h:outputText value="Model:" />
<h:outputText value="#{carBean.selectedCar.year}" />
</h:panelGrid>
</p:dialog>
</h:form>

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.

Resources