Primefaces 5.0, JSF 2.2, Wildfly 8.1
The following use case:
Click a command button in a view (with some parameters)
The bean method looks something up in the database - if necessary dialog1 is shown. In dialog1 there is a form and a command button.
The command button in dialog1 is clicked, the bean method looks something up in the database.
Dialog1 is closed and dialog2, depending on the result of the bean method, is shown.
bean1.java:
public void buttonClicked() {
Map<String, Object> options = new HashMap<>();
options.put("modal", true);
options.put("widgetVar", "dialog1");
options.put("id", "dlg1");
if(somethingTrue()) {
RequestContext.getCurrentInstance().openDialog("dialog1.xhtml", options, null);
}
}
Everything fine. Dialog1 shows up.
dialog1.xhtml:
<h:body>
<h:form>
<p:commandButton value="Button" actionListener="#{bean2.dialog1ButtonClicked}" />
</h:form>
</h:body>
bean2.java:
public void dialog1ButtonClicked() {
Map<String, Object> options = new HashMap<>();
options.put("modal", true);
options.put("widgetVar", "dialog2");
options.put("id", "dlg2");
if(somethingTrue()) {
RequestContext.getCurrentInstance().openDialog("dialog2.xhtml", options, null);
}
}
dialog2.xhtml:
<h:body>
The operation was successful.
</h:body>
Dialog2 shows up within dialog1!
How can I close dialog1 and show dialog2 NOT within dialog1?
I tried closing dialog1 with Primefaces Dialog Framework before opening dialog2:
RequestContext.getCurrentInstance().closeDialog(null);
RequestContext.getCurrentInstance().openDialog("dialog2.xhtml", options, null);
Dialog2 doesn't show up.
I tried opening dialog2 after the AJAX callback <p:ajax event="dialogReturn" listener="#{bean1.dialogClosed}"/>
Dialog2 doesn't show.
I tried the client side Java Script call: onclick="PF('dialog1').hide()"
Dialog2 still shows up nested into dialog1.
using onHide you can open another dialog like this.
<p:dialog class="userRegisterDialog" header="#{bean.dailogHeader}" modal="true" resizable="false" draggable="false" onHide="PF('dialog2').show();>
</p:dialog>
It also work when close dialog using escape key.
Solution:
Open just one dialog:
RequestContext.getCurrentInstance().openDialog("dialog1.xhtml", options, null);
The dialog flow is controlled by an ajax update of the main panel, where the rendered attribute is bound to a bean property and therefore completely controlled by the bean.
dialog1.xhtml:
<p:dialog class="userRegisterDialog" header="#{bean.dailogHeader}"
modal="true" resizable="false" draggable="false">
<p:ajax event="close" listener="#{bean2.closeRegistration}" update=":update"/>
<p:panel id="update">
<p:panel id="step1" rendered="#{bean.showStep1}">
<h:form>
<p:commandButton class="continueButton" value="Button1" actionListener="#{bean.doStep1}" update=":update"/>
</h:form>
</p:panel>
<p:panel id="step2" rendered="#{bean.showStep2}">
<h:form>
<p:commandButton class="closeButton" value="Button2" actionListener="#{bean.doStep2}" update=":update"/>
</h:form>
</p:panel>
</p:panel>
</p:dialog>
The dialog bean:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
#ManagedBean
#ViewScoped
public class Bean implements Serializable
{
private boolean showStep1 = true;
private boolean showStep2 = false;
public void doStep1(ActionEvent actionEvent) {
if(doSomething())
{
setShowStep1(false);
setShowStep2(true);
}
}
public void doStep2(ActionEvent actionEvent) {
if(doSomething2())
{
RequestContext.getCurrentInstance().closeDialog(null);
}
}
// Getter and setter ...
}
Another bean for the dialog closing:
#ManagedBean
#RequestScoped
public class Bean2 implements Serializable {
public void closeRegistration() {
FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove("bean");
}
}
The method closeRegistration removes the viewscoped bean. Therefore another call of the the dialog within the same page will start the dialog flow from the beginning.
we can close on dialog in onsuccess or onerror or oncomplete also. Check the image for your reference
Related
Primefaces 4.0
I need to reset the initial disable-state of components contained in a p:dialog.
The following simplified example shows the problem:
XTML:
<p:dialog header="header" widgetVar="dialog" appendTo="#(body)"
modal="true" resizable="false">
<h:form id="form">
<p:inputText value="#{bean.text}" id="text" />
<p:commandButton value="Disable InputText"
action="#{bean.disableInputText}" />
<p:commandButton value="Cancel"
action="#{bean.cancelDialog}"
process="#this"
update="#form" immediate="true">
<p:resetInput target="#form"/>
</p:commandButton>
</h:form>
</p:dialog>
ManagedBean:
#ViewScoped
public class Bean {
public void disableText() {
final FacesContext context = FacesContext.getCurrentInstance();
final UIViewRoot root = context.getViewRoot();
final UIComponent component = root.findComponent(":text");
if (uiComponent instanceof InputText) {
((InputText) uiComponent).setDisabled(true);
}
}
public void cancel() {
// reset disable-state of the disable-state of all components in a generic way.
}
}
While using the dialog the p:inputText element can be disabled. If the dialog was canceled and opened again, inputText should not disabled. The initial state should have been restored. Please note that this example is simplified and i am looking for a general solution that also works with a formular with 10+ input elements.
The general (and broadest) solution
For a general solution you can use the state saving functionality that is available in Java Server Faces. Using your code example as a base (with some minor changes to clean things up), here is an example that uses state saving and restores the previous state of the component;
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Disable Test</title>
</h:head>
<h:body>
<p:dialog header="header" widgetVar="dialog" appendTo="#(body)" modal="true" resizable="false">
<h:form id="form">
<p:inputText value="#{disableTestBean.text}" id="text"/>
<p:commandButton value="Disable InputText" action="#{disableTestBean.onDisable}" update="#form" />
<p:commandButton value="Cancel" action="#{disableTestBean.onCancel}" update="#form" onsuccess="PF('dialog').hide()" />
</h:form>
</p:dialog>
<button onclick="PF('dialog').show()">Open</button>
</h:body>
</html>
To actually see the reset happening, get rid of the onsuccess attribute from the second commandButton - as it currently closes the dialog.
#Data
#Named
#ViewScoped
public class DisableTestBean implements Serializable {
private String text;
private Object prevState;
private UIComponent findComponent(String where) {
final FacesContext context = FacesContext.getCurrentInstance();
final UIViewRoot root = context.getViewRoot();
return (UIComponent) root.findComponent(where);
}
public void onDisable() {
final InputText component = (InputText) findComponent(":form:text");
component.setDisabled(false);
component.setValue("");
prevState = component.saveState(FacesContext.getCurrentInstance());
component.setValue("meh");
component.setDisabled(true);
}
public void onCancel() throws IOException {
final InputText component = (InputText) findComponent(":form:text");
component.restoreState(FacesContext.getCurrentInstance(), prevState);
}
}
The example targets one specific input component. However, if you need to handle multiple components, you can easily use a loop to accomplish what you want in a general way.
As a demonstration I not only reset the disabled state in the backing bean above, but also the value (content) of the input component. This demonstrates you how you can actually reset the complete state of the component (not only a single attribute or value). So the solution is broad and very general.
The second more direct approach
The second approach is to do what #Kukeltje is hinting at in his comments above. Use the disabled= attribute on the input components and have a backing bean value that just changes the value to false when you press Cancel. This is not as general and wont work for everything else, but it will do the job in your particular use case. If you are only interested in the disabled state it's probably even the prefered way of doing it. If you want an example of that as well, I can extend this answer - just let me know.
I am seeing different behaviors of and in a page containing multiple forms.
Here is my backing bean:
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class MultiFormBean
{
String inputText1 = "";
String inputText2 = "";
#PostConstruct
public void initializeBean(){
System.out.println("PostConstruct Called ------------------");
}
public String getInputText1()
{
return inputText1;
}
public void setInputText1(String inputText1)
{
this.inputText1 = inputText1;
}
public String getInputText2()
{
return inputText2;
}
public void setInputText2(String inputText2)
{
this.inputText2 = inputText2;
}
public void doSubmit1() {
inputText2 = inputText1;
}
public void doSubmit2() {
inputText1 = inputText2;
}
}
When i use the following xhtml , clicking Submit1 and Submit2 any number of times won't call #PostConstruct more than once:
<h:body>
<h:form id="firstForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget1"/>
<h:inputText id="first_input" value="#{multiFormBean.inputText1}"/>
<h:commandButton id="click1" action="#{multiFormBean.doSubmit1}" value="submit1" type="submit"
onclick="javascript:jsf.ajax.request(this, event, {execute:'firstForm', render:'renderTarget1 secondForm'}); return false;">
</h:commandButton>
</h:form>
<h:form id="secondForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget2"/>
<h:inputText id="second_input" value="#{multiFormBean.inputText2}"/>
<h:commandButton id="click2" action="#{multiFormBean.doSubmit2}" value="submit2" type="submit"
onclick="javascript:jsf.ajax.request(this, event, {execute:'secondForm', render:'renderTarget2 firstForm'}); return false;">
</h:commandButton>
</h:form>
</h:body>
But the following xhtml would call #PostConstruct more than once:
<h:body>
<h:form id="firstForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget1"/>
<h:inputText id="first_input" value="#{multiFormBean.inputText1}"/>
<a4j:commandButton id="click1" action="#{multiFormBean.doSubmit1}" value="submit1" type="submit" execute="#form" render="renderTarget1,secondForm"/>
</h:form>
<h:form id="secondForm" prependId="false">
<h:panelGroup layout="block" id="renderTarget2"/>
<h:inputText id="second_input" value="#{multiFormBean.inputText2}"/>
<a4j:commandButton id="click2" action="#{multiFormBean.doSubmit2}" value="submit2" type="submit" execute="#form" render="renderTarget2,firstForm"/>
</h:form>
</h:body>
Please can anyone help me use the <a4j:commandButton> instead of <h:commandButton>
Also i see that i cannot call the method doSubmit2() with a4j commandButton
I think that problem here is in bug inside JSF2 and Richfaces4. From 4 version Richfaces started using JSF embedded ajax capabilities. And There is a bug with using multiple forms on page with ajax requests. The problem there that richfaces renders special hidden input with the id of currently rendered view state. This id is changed when new view is rendered. And it is also submitted with every request to show that it belongs to some specific view. So when you have multiple forms on the same page after first ajax request the view state is getting the wrong place and it can be not submitted again second time. Sometimes behavior looks like very very wierd with no logical description.
PostConstruct is called twice because server thinks that two requests belong to different views(view state is not sumbitted) and as far as bean is view scoped it is created twice. After clicking aroung ajax can completelly stop working with this because server woukd not recognize the view(probably what you see when you can not click second submit button).
In the first place I recommend you to use latest available version of JSF and Richfaces. This bug (and many more) may be already fixed there.
This question already has answers here:
p:commandbutton action doesn't work inside p:dialog
(4 answers)
Closed 6 years ago.
I have a problem. I have a form
with inputs to be sent to a bean by , the thing is debugged, in the bean object is always null. Could you help me with this.
Here the code:
<h:form id="frmNuevo">
<p:dialog id="dialog" header="AƱadir Presupuesto" widgetVar="dialogNuevo" resizable="true" width="500" height="500" showEffect="fade" hideEffect="explode" modal="true">
<p:growl id="growl" showDetail="true" sticky="true" />
<h:panelGrid id="display" columns="2" cellpadding="4" style="margin: 0 auto;">
<h:outputText value="Diciembre:" />
<p:inputText value="#{presupuestoBean.presupuesto.diciembre}" required="true" maxlength="20" />
<p:commandButton value="Guardar" update=":form:cars, frmNuevo, growl, display" process="#this" actionListener="#{presupuestoBean.insertar}" oncomplete="dialogNuevo.hide()" image="icon-save" />
<p:commandButton value="Cancelar" update=":form:cars" oncomplete="dialogNuevo.hide()" style="margin-bottom: 20px;" image="icon-cancel" />
</h:panelGrid>
<p:separator/></p:dialog>
</h:form>
I tested with SessionScoped and RequestScoped and does not work, the strange thing is I have done other similar beans and if they work
ManagedBean:
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
#ManagedBean(name = "presupuestoBean")
#RequestScoped
public class PresupuestoBean implements Serializable {
private TbPresupuesto presupuesto;
private List<TbPresupuesto> presupuestos;
private UploadedFile file;
private String destination = "C:\\temp\\";
public PresupuestoBean() {
presupuesto = new TbPresupuesto();
presupuestos = new ArrayList();
}
public TbPresupuesto getPresupuesto() {
return presupuesto;
}
public void setPresupuesto(TbPresupuesto presupuesto) {
this.presupuesto = presupuesto;
}
public void prepararInsertar() {
presupuesto = new TbPresupuesto();
presupuestos = new ArrayList();
}
public void insertar() {
PresupuestoDaoImpl presupuestoDao = new PresupuestoDaoImpl();
presupuesto.setPresupuestoId(presupuesto.getLinea().getLineaId());
presupuestoDao.insertar(presupuesto);
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Se ha ingresado correctamente"));
presupuesto = new TbPresupuesto();
}
}
The form must go inside the dialog.
<p:dialog>
<h:form>
...
</h:form>
</p:dialog>
The generated HTML representation of the dialog component is namely during page load by JavaScript relocated to the end of <body> in order to improve cross browser compatibility of presenting a modal dialog.
With your current code, this thus means that the dialog will then not sit in a form anymore. So when you try to submit the input values inside the dialog, they will end up as nulls because there is no form in order to collect and send the input values to the server.
Further, you're only processing the submit button inside the command button.
<p:commandButton ... process="#this" />
Remove that attribute. It defaults to #form already, which is exactly what you want.
I have two primefaces panel components in jsf page.I want to show some data on panels via clicking primefaces commandButton and show panel1 when page load.When clicking commandbutton,I do not want to show other panel.So I defined boolean variables in backing bean to use in visible property of panels.But it does not work.
Backing Bean:
#ManagedBean
#SessionScoped
public class Bean implements Serializable {
private boolean show;
#PostConstruct
public void init(){
this.show=true;
}
public void action_commandButton(){
this.show=false;
}
}
Jsf Page
<p:commandButton style="text-align: center;font-size:12px;"
action="#{bean.action_commandButton()}" value=""/>
<!--panel 1 -->
<p:panel visible="#{bean.show}">
<p:dataGrid>
<!-- data from datbase-->
</p:dataGrid>
</p:panel>
<!-- panel 2-->
<p:panel visible="#{!bean.show}">
<p:dataGrid>
<!-- data from datbase-->
</p:dataGrid>
</p:panel>
How to solve this problem?
Thanks in advance.
h:commandButton action not worked in modalPanel.
I am using t:inputFileUpload component for upload file. In my richModalPanel have one h:commandButton
My requirement : After browse the file, and click upload commandButton, then i want to show the selected file name in inside ModalPanel.
My problem is :
When i click commandbutton in modalPanel, not called commandButton action in bean, and automattically close the modalPanel.
In that action method starting...just i put System.out.println("Uploading process to be start..."); Even this output not print in my tomcat log.
<body>
<h:form id="UploadForm" binding="#{FileUpload.intiForm}">
<a4j:outputPanel id="uploadOutputPanel">
<a4j:commandButton value="ShowModalPanel"
action="#{FileUpload.showUploadPanelAction}"
oncomplete="#{rich:component('uploadImagePanel')}.show()"
reRender="uploadImagePanel,uploadOutputPanel"/>
</a4j:outputPanel>
</h:form>
<rich:modalPanel id="uploadImagePanel" moveable="true" top="150" width="400" autosized="true">
<h:form id="uploadForm" enctype="multipart/form-data" >
<h:panelGrid id="uploadPanelGridId" columns="2">
<t:inputFileUpload id="uploadFile"
value="#{FileUpload.logoImageFile}"
size="54"/>
<h:commandButton id="UploadButton"
value="Upload"
action="#{FileUpload.uploadFileAction}"/>
<h:outputText value="Uploaded File Name : #{FileUpload.fileName}"/>
</h:panelGrid>
</h:form> </rich:modalPanel> </body>
faces-config.xml
<managed-bean>
<managed-bean-name>FileUpload</managed-bean-name>
<managed-bean-class>com.jsf.fileupload.FileUpload</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
FileUpload .java
import javax.faces.component.html.HtmlForm;
import org.apache.myfaces.custom.fileupload.UploadedFile;
public class FileUpload
{
private HtmlForm intiForm;
private String fileName;
private UploadedFile logoImageFile;
public String showUploadPanelAction()
{
System.out.println("Show Upload Panel Action ....."); //This line showing in tomcat log, when i click "ShowModalPanel" button --> a4j:commandButton
return "";
}
public String uploadFileAction()
{
System.out.println("Uploading process to be start...."); //But this line NOT show in my tomcat log, when i click "UploadButton" --> h:commandButton
System.out.println("logoImageFile : " + logoImageFile);
if(logoImageFile != null)
{
fileName = logoImageFile.getName();
}
return "";
}
public HtmlForm getIntiForm(){
System.out.println("Page initializing......"); //This line showing in tomcat log, when the page loading time
return intiForm;
}
public void setIntiForm(HtmlForm intiForm) {
this.intiForm = intiForm;
}
public UploadedFile getLogoImageFile(){
return logoImageFile;
}
public void setLogoImageFile(UploadedFile logoImageFile){
this.logoImageFile = logoImageFile;
}
public String getFileName(){
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
Please help me..
Thanks in advance.
Use domElementAttachment="form" to the modal panel
<rich:modalPanel id="uploadImagePanel" moveable="true" top="150" width="400" autosized="true" domElementAttachment="form"> </rich:modalPanel>
Do the other prints show up in your log ?
Have you annotated your FileUpload.java with #Named or #ManagedBean ? And its #{fileUpload.xxx}, not #{FileUpload.xxx}.
And i would also change
<h:commandButton id="UploadButton"
value="Upload"
action="#{FileUpload.uploadFileAction}"/>
with an
<a4j:commandButton id="UploadButton"
value="Upload"
action="#{FileUpload.uploadFileAction}"
reRender="uploadImagePanel,uploadOutputPanel">
I'm not sure if they are related but i'm facing a similar issue when using and h:commandLink inside a form with enctype="multipart/form-data". If I remove this property from the form it works.