I have a strange behavior where I am getting NPE while doing page refresh using faces context.
I have a managed bean which is in Request Scope. So want to refresh the page after click on commandbutton. I have tried with 'update' but it is behaving strange in my page.
Error: PartialViewContextImpl$PhaseAwareVisitCallback.visit : java.lang.NullPointerException
This is my JSF page:
<h:form id="form">
<p:messages autoUpdate="true"/>
<h:panelGrid columns="4" cellpadding="5" id="panelGrid" rendered="true">
<p:outputLabel for="s00" value="#{tk.expense_keyword}"/>
<p:inputText id="s00" value="#{expense.form.keyword}"/>
<p:outputLabel for="s02" value="#{tk.expense_creatorId}"/>
<p:inputText id="s02" value="#{expense.form.creatorId}" disabled="#{!expense.form.canEditCreatorId}"/>
<h:outputText id="s10" value="Amount Between #{expense.form.amountFrom} and #{expense.form.amountTo}" />
<h:panelGrid>
<p:slider for="s11,s12" display="s10" minValue="0" maxValue="1000" style="width: 200px" range="true" displayTemplate="Amount Between {min} and {max}" />
<h:inputHidden id="s11" value="#{expense.form.amountFrom}" />
<h:inputHidden id="s12" value="#{expense.form.amountTo}" />
</h:panelGrid>
</h:panelGrid>
<p:commandButton value="#{tk.expense_search}" id="a01" action="#{expense.search}" ajax="false" immediate="true"/>
<p:dataTable var="line" varStatus="loop" value="#{expense.form.expenseEntryList}" emptyMessage="#{tk.expense_table_empty}" id="dataTable">
<p:column headerText="#{tk.expense_table_creatorId}">
<h:inputHidden value="#{line.oid}"/>
<h:inputText value="#{line.creatorId}"/>
</p:column>
<f:facet name="footer">
<p:commandButton value="#{tk.expense_saveAsDraft}" id="a06" action="#{expense.saveAsDraft}"/>
<p:commandButton value="#{tk.expense_submit}" id="a07" action="#{expense.submitAll}"/>
<p:commandButton value="#{tk.expense_validate}" id="a08" action="#{expense.validate}"/>
</f:facet>
</p:dataTable>
</h:form>
Here when I click on Save As Draft I want to refresh the page. So I am using FacesContext's method to refresh the page.
Here is my method saveAsDraft:
public Outcome saveAsDraft() throws Exception{
try {
saveAsDraftBody(false,false);
getFacesContext().getPartialViewContext().getRenderIds().add("form:panelGrid");**//**getting error****
getFacesContext().getPartialViewContext().getRenderIds().add("form:dataTable");**//**works fine****
Log.info(this,"getFacesContext().getPartialViewContext().getRenderIds(): "+getFacesContext().getPartialViewContext().getRenderIds());
return Outcome.SUCCESS;
}
catch (Throwable e){
throw manageError(e);
}
}
I don't know why it works for data table refresh but not for panelGrid :(
First of all you have the bean in request scope and you are making full page submit and here the partial render does not make any sense. The error you are getting because you have component which is basically, another input into a form which will be sent to the managed bean of the current view when the form is submitted.
Related
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.
I have a JSF application using Primefaces 3.5. I have a page where after click in a commandButton I call a method in Managed Bean which will fill a list that will be showed in fields tblPerfis and txtPerfis below.
<ui:composition template="...">
<ui:define name="content">
<h:form id="formPrincipal">
<br />
<p:fieldset legend="Pesquisa de Perfil" >
<p:panelGrid columns="2" >
<f:facet name="footer">
<p:commandButton id="btnPesquisar"
actionListener="#{perfilAcessoMB.pesquisar}" value="Pesquisar"
update="tblPerfis txtPerfis pnlPerfis"
styleClass="ui-icon-search" />
</f:facet>
</p:panelGrid>
</p:fieldset>
<br />
<h:outputText id="txtPerfis" value="Perfis: #{perfilAcessoMB.perfis}" ></h:outputText>
<p:dataTable id="tblPerfis" value="#{perfilAcessoMB.perfis}" var="perfil" emptyMessage="Nenhum perfil encontrado." >
<p:column headerText="Nome">
<h:outputText value="#{perfil.descricao}"></h:outputText>
</p:column>
</p:dataTable>
<p:outputPanel id="pnlPerfis">
<p:fieldset id="resultadoPesquisa" legend="Resultado da Pesquisa">TESTE</p:fieldset>
</p:outputPanel>
</h:form>
</ui:define>
</ui:composition>
The called method is the follow:
#ManagedBean
#ViewScoped
public class PerfilAcessoMB {
public void pesquisar(ActionEvent event) {
// Fill perfis List
}
}
At principle, it works as waited. My problem happens when I want add rendered attribute:
<h:outputText id="txtPerfis" value="Perfis: #{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" ></h:outputText>
<p:dataTable id="tblPerfis" value="#{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" var="perfil" emptyMessage="Nenhum perfil encontrado." >
<p:column headerText="Nome">
<h:outputText value="#{perfil.descricao}"></h:outputText>
</p:column>
</p:dataTable>
<p:outputPanel id="pnlPerfis" rendered="#{not empty perfilAcessoMB.perfis}">
<p:fieldset id="resultadoPesquisa" legend="Resultado da Pesquisa">TESTE</p:fieldset>
</p:outputPanel>
Even when there is results, these fields are not showed. Does someone have any idea what is happening here?
Thanks,
Rafael Afonso
EDIT
Following a workmate suggestion, I changed the code to put dataTable and outputText inside outputPanel. The commandButton will reference the outputPanel but the rendered attibute will be put in datatable and outputText.
<p:commandButton id="btnPesquisar"
actionListener="#{perfilAcessoMB.pesquisar}" value="Pesquisar"
update="pnlPerfis"
styleClass="ui-icon-search" />
<p:outputPanel id="pnlPerfis">
<h:outputText id="txtPerfis" value="Perfis: #{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" ></h:outputText>
<p:dataTable id="tblPerfis" value="#{perfilAcessoMB.perfis}" rendered="#{not empty perfilAcessoMB.perfis}" var="perfil" emptyMessage="Nenhum perfil encontrado." >
<p:column headerText="Nome">
<h:outputText value="#{perfil.descricao}"></h:outputText>
</p:column>
</p:dataTable>
</p:outputPanel>
After this, the page worked as waited.
However, I still did not understand what happened. What is the explanation for this behaviour?
Your problem occurs because our table is not rendered it simply does not exist in your html code, that is not in this context to be found to update or another source.
When you shut a larger scope as the panel and force an update in this it forces the table to check the condition for rendering, if yes the code is written and can be seen without problems.
I have this form with a panel grid and a dialog:
<h:form id="regiForm">
<p:panelGrid>
<p:row style="height:30%">
<p:column>
<h:outputText/>
</p:column>
<p:column>
<p:commandButton style="width:350px" type="submit" actionListener="#
{regiBean.showDialog}" id="ajax" value="#{msg['regi_button']}" update="regiForm" process="#this"/>
</p:column>
<p:column>
</p:column>
</p:row>
</p:panelGrid>
<p:dialog id="dialog" header="#{msg['regi_dialog_header']}" widgetVar="myDialog" position="center center" >
<h:outputText value="#{msg['regi_dialog']}" />
</p:dialog>
</h:form>
I would like to open the dialog from inside the action listener:
public void showDialog() {
RequestContext.getCurrentInstance().execute("dialog.show()");
RequestContext.getCurrentInstance().execute("myDialog.show()");
}
However, the dialog is not shown. How is this caused and how can I solve it?
I'm using JSF 2.1 and PrimeFaces 3.5.
The first statement with the command
RequestContext.getCurrentInstance().execute("dialog.show()");
won't work because dialog refers to the XHTML ID of the p:dialog component. This will cause an javascript error. And that could be the reason why the second command
RequestContext.getCurrentInstance().execute("myDialog.show()");
won't get executed.
Also I would add ; to the end of each Javascript command (but this is just my personal style)
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>
I have a simple flow in my appliaction - if you fill out and press save on one form (if everything goes well) you are redirected to a second view with a list. Now I wanted to add a message saying "You successfuly added an object" but since I'm using a redirect from what I remember I need to use the Flash scope. And so I did. The problem is that during the first "save" it correctly shows only 1 message but when I navigate back to the form and hit "save" it will show me the current message and the old one! It's even stranger that when (for the 3rd time) I go back to the form and hit "save" I again get only 1 message (and so on 1-2-1-2-1-2 etc...). Am I doing something wrong or is it a bug in jsf? I mean my I'm calling the same method and get different results...
I'm using primefaces and the newest mojarr:
jsf-api-2.1.1-b04
jsf-impl-2.1.1-b04
primefaces-2.2.1
Here's the code (most relevant parts at least):
SaveForm.xhtml:
<div id="content-box" class="content-box">
<p:panel id="content-panel" header="Dane raportu"
styleClass="content-panel">
<div class="content-box">
<h:form prependId="false">
<h:panelGrid id="grid" columns="2" styleClass="content-panel">
<!-- some inputs and labels -->
<p:commandButton value="#{msg['thesis.save.button']}"
action="#{thesisBean.saveThesis}" />
</h:panelGrid>
</h:form>
</div>
</p:panel>
</div>
saveThesis method:
public String saveThesis() {
//this creates a Hibernate entity and saves it to the DB
thesisService.addThesis(createThesisEntity());
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getFlash().setKeepMessages(true);
ResourceBundle bundle = context.getApplication().getResourceBundle(
context, "msg");
context.addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, "key1",
"key2"));
return "list-theses.xhtml?faces-redirect=true";
}
list-theses.xhtml:
<ui:composition template="/basicTemplate.xhtml">
<ui:define name="content">
<p:growl id="growl" showDetail="true" sticky="false" life="5000" />
<div id="content-box" class="content-box">
<h:form prependId="false" id="table-form">
<p:dataTable var="thesis" value="#{thesisTableBean.theses}"
paginator="true" rows="20">
<p:column styleClass="table-name-column">
<f:facet name="header">
<h:outputText value="#{msg['thesis.table.name.header']}" />
</f:facet>
<h:outputText value="#{thesis.firstName} #{thesis.lastName}" />
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="#{msg['thesis.table.title.header']}" />
</f:facet>
<h:outputText value="${thesis.title}" />
</p:column>
<p:column styleClass="table-number-column">
<f:facet name="header">
<h:outputText value="#{msg['thesis.table.number.header']}" />
</f:facet>
<h:outputText value="${thesis.number}" />
</p:column>
</p:dataTable>
</h:form>
</div>
</ui:define>
Well I found a "solution" here: http://ocpsoft.com/java/persist-and-pass-facesmessages-over-page-redirects/ Seems to work pretty well. Still I have no idea why my code isn't working. I mean it's the same method every time but the result differs...