I'm trying to set a dialog title at runtime (dynamically) but update with #widgetVar expression cannot do the trick. Any ideas?
The first command button renders the dialog with the dynamic title but the second command fail to render the title! Why? Here the example is simplified but the real page is more complex and it is difficult to specify the id of the dialog to render.
<h:form>
<p:commandButton value="Basic" ajax="true" process="#this"
update=":dlg1" oncomplete="PF('widget-dialog').show();"
actionListener="#{dialogView.changeTitle('Dynamic title')}" />
<p:commandButton value="Widget" ajax="true" process="#this"
update="#widgetVar('widget-dialog')"
oncomplete="PF('widget-dialog-1').show();"
actionListener="#{dialogView.changeTitle('Dynamic title')}" />
</h:form>
<p:dialog id="dlg1" header="#{dialogView.title}"
widgetVar="widget-dialog" dynamic="true">
<h:outputText value="Resistance to PrimeFaces is futile!!!" />
</p:dialog>
#ManagedBean(name = "dialogView")
#ViewScoped
public class DialogView {
private String title = null;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public void changeTitle(String title) {
setTitle(title);
}
}
Related
Prerequisites:
- JSF 2.1
- Primefaces 5.2
- Glassfish 3.1
Story:
I've created a p:dialog used for displaying FacesMessages on a p:messages element. This dialog is needed, because the user has to commit specific FacesMessages with an "OK"-Button before proceeding.
Dialog:
<p:outputPanel id="modalMessage">
<p:dialog id="dlgMessageDialog" dynamic="true" style="z-index: 100"
closable="false" widgetVar="wigVarMessageDialog" modal="true"
appendTo="#(body)">
<f:facet name="header">
<h:outputText id="messageDialogHeader"
value="#{messageDialogBean.header}" />
</f:facet>
<p:outputPanel id="modalMessagePanel">
<h:form id="messageForm" enctype="multipart/form-data">
<p:messages id="messages" escape="false" closable="false"
showDetail="true" autoUpdate="true"
for="#{messageDialogBean.messageDialogId}"></p:messages>
<p:spacer height="20px"></p:spacer>
<p:commandButton value="#{msg.btnOk}"
oncomplete="PF('wigVarMessageDialog').hide()" />
</h:form>
</p:outputPanel>
</p:dialog>
</p:outputPanel>
Bean:
#Named("messageDialogBean")
#SessionScoped
public class MessageDialogBean implements Serializable {
private static final long serialVersionUID = 1L;
private final String messageDialogId = "messageDialogId";
private FacesMessage message = new FacesMessage();
private String header = "test";
public void showMessage(final String pHeader, final FacesMessage pMessage) {
if (pMessage != null) {
setHeader(pHeader);
this.message = pMessage;
show();
}
}
public void showWarn(final String pHeader, final String pSummary, final String pDetail) {
setHeader(pHeader);
this.message = new FacesMessage(FacesMessage.SEVERITY_WARN, pSummary, pDetail);
show();
}
public void showInfo(final String pHeader, final String pSummary, final String pDetail) {
setHeader(pHeader);
this.message = new FacesMessage(FacesMessage.SEVERITY_INFO, pSummary, pDetail);
show();
}
public void showError(final String pHeader, final String pSummary, final String pDetail) {
setHeader(pHeader);
this.message = new FacesMessage(FacesMessage.SEVERITY_ERROR, pSummary, pDetail);
show();
}
public void updateDialog() {
RequestContext context = RequestContext.getCurrentInstance();
context.update("mainForm:messageDialogHeader");
}
private void show() {
updateDialog();
RequestContext context = RequestContext.getCurrentInstance();
context.execute("PF('wigVarMessageDialog').show();");
FacesContext.getCurrentInstance().addMessage(this.messageDialogId, this.message);
}
public String getMessageDialogId() {
return this.messageDialogId;
}
public void setHeader(final String pHeader) {
this.header = pHeader;
}
public String getHeader() {
return this.header;
}
public FacesMessage getLastMessage() {
return this.message;
}
}
One of the messages which have to be commited:
this.messageDialogBean.showInfo("Title", "Summary", "Detail");
Problem:
The p:messages element of the dialog does not show the message when the dialog is opened the first time. After opening and hiding it once it shows all further FacesMessages just fine.
Question:
So far i am useing opening and closeing the dialog once when the interface is initialized as a workarround. Does annyone know what causes this problem in the first place and also how to solve it properly?
Thanks for answers
First of all it is not allowed to put a form inside of another, as stated in W3C XHTML specification, "form must not contain other form elements." visit: https://www.w3.org/TR/xhtml1/#prohibitions.
So your dialog should not be inside of the main form, you have to sperate the dialog from the form, your code sould be orginsed like this :
<form id="mainForm" >
<!--your main page-->
</form>
<p:dialog id="dlgMessageDialog" >
<h:form id="messageForm" enctype="multipart/form-data">
<f:facet name="header">
<h:outputText id="messageDialogHeader"
value="#{messageDialogBean.header}" />
</f:facet>
<p:messages id="messages" escape="false" closable="false"
showDetail="true" autoUpdate="true"
for="#{messageDialogBean.messageDialogId}"></p:messages>
<p:spacer height="20px"></p:spacer>
<p:commandButton value="#{msg.btnOk}"
oncomplete="PF('wigVarMessageDialog').hide()" />
</h:form>
</p:dialog>
Another thing, you have to update the whole dialog, so when the dialog is opened the messges is automaticly updated :
context.update("dlgMessageDialog");
I have the following Java code:
#Named
#SessionScoped
public class TestClass implements Serializable {
private String stringValue;
#PostConstruct
private void init() {
initStringValueDefault();
}
public void initStringValue1() {
stringValue = "ABCD";
}
public void initStringValue2() {
stringValue = "EFGH" + '\u001c';
}
public void initStringValueDefault() {
stringValue = "LABEL TEXT";
}
public String getStringValue() {
return stringValue;
}
}
and .xhtml
<h:form id="testForm" prependId="true">
<h:outputText id="stringValueLabel" value="#{testClass.stringValue}" escape="false"/>
<br/>
<h:commandButton value="Set ABCD" actionListener="#{testClass.initStringValue1()}">
<f:ajax execute="#form" render="stringValueLabel"/>
</h:commandButton>
<span style="margin-left: 10px"/>
<h:commandButton value="Set EFGH + \u001c" actionListener="#{testClass.initStringValue2()}">
<f:ajax execute="#form" render="stringValueLabel"/>
</h:commandButton>
<span style="margin-left: 10px"/>
<h:commandButton value="Set default" actionListener="#{testClass.initStringValueDefault()}">
<f:ajax execute="#form" render="stringValueLabel"/>
</h:commandButton>
</h:form>
When I click on the 'Set ABCD' button, update works successfully. But after click on the 'Set EFGH + \u001c' I get errors:
Chrome: 'The page at localhost:8080 says: emptyResponse: An empty response was received from the server.'
Firefox: 'malformedXML: XML Parsing Error: not well-formed'
and the label haven't been updated. And after page reload the label updates to 'EFGH'.
Anybody knows, why due to adding '\u001c' to the variable, update doesn't work after button click?
With escape="true" everything works fine, but I need escape="false".
The problem was solved by treating the variable with method escapeXml11(String input) of org.apache.commons.lang3.StringEscapeUtils:
import static org.apache.commons.lang3.StringEscapeUtils.escapeXml11;
...
public void initStringValue2() {
stringValue = "EFGH" + '\u001c';
stringValue = escapeXml11(stringValue);
}
...
I am trying to add a PrimeFaces <p:tab> dynamically. While adding the second tab I am getting the following exception:
"java.lang.IllegalStateException: Component ID tab0 has already been found in the view".
How can I solve this?
Here is the view code:
<h:form prependId="false">
<p:tabView id="tabview" dynamic="true" cache="false"
binding="#{testBean.tabView}"
activeIndex="#{testBean.activeTab}" >
<h:commandButton value="Close" action="#{testBean.removeTab}"/>
</p:tabView>
<h:commandButton value="Add Tab" action="#{testBean.addTab}"/>
</h:form>
Here is the bean code:
public String addTab() {
String tabId="tab"+id;
System.out.println("Gen Id: "+tabId);
tab = new Tab();
tab.setTitle("Title: "+tabId);
tab.setId(tabId);
System.out.println("Tab Id: "+tab.getId());
tabView.getChildren().add(id,this.tab);
id++;
return "tabtest.jsf";
}
public String removeTab() {
tabView.getChildren().remove(activeTab);
return "tabtest.jsf";
}
Don't manually create components if everything can just be done in the view. This construct will fail if the bean is in a broader scope than the request scope. See also e.g. Binding attribute causes duplicate component ID found in the view
Follow the showcase example "TabView with Model" which allows you to dynamically populate tabs via a sane model and <p:tabView value="..." var="..."> like as <ui:repeat>/<h:dataTable>.
E.g. this view
<h:form>
<p:tabView value="#{bean.tabs}" var="tab">
<p:tab title="#{tab.title}">
#{tab.content}
<p:commandButton value="Close" action="#{bean.remove(tab)}" update="#form" />
</p:tab>
</p:tabView>
<p:commandButton value="Add Tab" action="#{bean.add}" update="#form" />
</h:form>
with this controller
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private List<Tab> tabs;
#PostConstruct
public void init() {
tabs = new ArrayList<>();
}
public void add() {
tabs.add(new Tab("tab" + tabs.size(), "some content"));
}
public void remove(Tab tab) {
tabs.remove(tab);
}
public List<Tab> getTabs() {
return tabs;
}
}
and this model
public class Tab {
private String title;
private String content;
public Tab(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
}
This is because same ID is being generated for new tab(The one which ur adding). To avoid this, append a variable to the id as
<p:tabView id="tabview_#{testBean.i}" dynamic="true" cache="false"binding="#{testBean.tabView}"
activeIndex="#{testBean.activeTab}" >
<h:commandButton value="Close" action="#{testBean.removeTab}"/>
</p:tabView>
I need show a value in an dialog after execute a method that I invoke in the commandbutton but the dialog don't show the variable value.
The variable value is calculate inside the commandbutton.
Managed bean
#ManagedBean
#ViewScoped
public class OrderBean implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void eventicus(ActionEvent event) {
this.name ="Value";
}
}
xhtml document
<h:commandButton actionListener="#{orderBean.calculate()}" value="Show" oncomplete="PF('dlg2').show();" />
<p:dialog id="modalDialog" header="Modal Dialog" widgetVar="dlg2" >
<h:panelGrid columns="2" style="margin-bottom:10px">
<h4><h:outputText value="#{orderBean.name}" /></h4>
</h:panelGrid>
<p:commandButton id="submitButton" value="Submit" oncomplete="PF('dlg2').hide();"/>
</p:dialog>
When I click in the commandbutton the dialog is empty.
1 I think you need to add a [update="modalDialog"] attribute inside your commandButton
I am trying to add a PrimeFaces <p:tab> dynamically. While adding the second tab I am getting the following exception:
"java.lang.IllegalStateException: Component ID tab0 has already been found in the view".
How can I solve this?
Here is the view code:
<h:form prependId="false">
<p:tabView id="tabview" dynamic="true" cache="false"
binding="#{testBean.tabView}"
activeIndex="#{testBean.activeTab}" >
<h:commandButton value="Close" action="#{testBean.removeTab}"/>
</p:tabView>
<h:commandButton value="Add Tab" action="#{testBean.addTab}"/>
</h:form>
Here is the bean code:
public String addTab() {
String tabId="tab"+id;
System.out.println("Gen Id: "+tabId);
tab = new Tab();
tab.setTitle("Title: "+tabId);
tab.setId(tabId);
System.out.println("Tab Id: "+tab.getId());
tabView.getChildren().add(id,this.tab);
id++;
return "tabtest.jsf";
}
public String removeTab() {
tabView.getChildren().remove(activeTab);
return "tabtest.jsf";
}
Don't manually create components if everything can just be done in the view. This construct will fail if the bean is in a broader scope than the request scope. See also e.g. Binding attribute causes duplicate component ID found in the view
Follow the showcase example "TabView with Model" which allows you to dynamically populate tabs via a sane model and <p:tabView value="..." var="..."> like as <ui:repeat>/<h:dataTable>.
E.g. this view
<h:form>
<p:tabView value="#{bean.tabs}" var="tab">
<p:tab title="#{tab.title}">
#{tab.content}
<p:commandButton value="Close" action="#{bean.remove(tab)}" update="#form" />
</p:tab>
</p:tabView>
<p:commandButton value="Add Tab" action="#{bean.add}" update="#form" />
</h:form>
with this controller
#ManagedBean
#ViewScoped
public class Bean implements Serializable {
private List<Tab> tabs;
#PostConstruct
public void init() {
tabs = new ArrayList<>();
}
public void add() {
tabs.add(new Tab("tab" + tabs.size(), "some content"));
}
public void remove(Tab tab) {
tabs.remove(tab);
}
public List<Tab> getTabs() {
return tabs;
}
}
and this model
public class Tab {
private String title;
private String content;
public Tab(String title, String content) {
this.title = title;
this.content = content;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
}
This is because same ID is being generated for new tab(The one which ur adding). To avoid this, append a variable to the id as
<p:tabView id="tabview_#{testBean.i}" dynamic="true" cache="false"binding="#{testBean.tabView}"
activeIndex="#{testBean.activeTab}" >
<h:commandButton value="Close" action="#{testBean.removeTab}"/>
</p:tabView>