I have a form with two date input fields. The first field named dateFrom always loses its value at page reload while the second one named dateTo works perfectly. When I fill both fields, both values are passed to the UI Bean, and both are successfully used to filter the view (a list of items). The UI Bean stores both values in a statusObject with session scope.
But after the page was updated, only dateTo is still filled while dateFrom one is empty. I've added some System.out.println()'s to the getters and settes of the values to see what happens and both setters are called with a value, then both getters return a value. The dateFrom field just ignores the value it gets from the UI Bean.
I'm using the date field provided by the browser, hence the a:type="date".
The page looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:a="http://xmlns.jcp.org/jsf/passthrough"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head/>
<h:body>
<ui:composition>
<f:loadBundle basename="de.myapp.Resources" var="bundle"/>
<!-- Some stuff removed for readability -->
<h:form enctype="multipart/form-data" id="filterForm">
<div class="filterBar">
<div class="filterElement">
<h:inputText a:type="date" id="dateFrom" size="8" maxlength="10"
value="#{myBean.dateFrom}"
converter="dateConverter"/>
</div>
<div class="filterElement">
<h:inputText a:type="date" id="dateTo" size="8" maxlength="10"
value="#{myBean.dateTo}"
converter="dateConverter"/>
</div>
</div>
<div class="filterElement">
<h:commandButton id="refreshButton"
action="#{myBean.refreshList}"
value=" #{bundle.refresh}"/>
</div>
</h:form>
<!-- Some more stuff removed for readability -->
</ui:composition>
</body>
</html>
I've checked that the words dateFrom and dateTo do not occur in the parts of the page I've removed.
Getters and setters in the UI Bean
public Date getDateFrom() {
System.out.println("getDateFrom() -> " + statusObjet.getDateFrom());
return statusObjet.getDateFrom();
}
public void setDateFrom(final Date dateFrom) {
if (dateFrom != null) {
System.out.println("setDateFrom( " + dateFrom + " )");
} else {
System.err.println("setDateFrom( NULL )"); // my IDE shows this colored red in the console
}
statusObjet.setDateFrom(dateFrom);
}
public Date getDateTo() {
System.out.println("getDateTo() -> " + statusObjet.getDateTo());
return statusObjet.getDateTo();
}
public void setDateTo(final Date dateTo) {
if (dateTo != null) {
System.out.println("setDateTo( " + dateTo + " )");
} else {
System.err.println("setDateTo( NULL )"); // my IDE shows this colored red in the console
}
statusObjet.setDateTo(dateTo);
}
Except the ID and the value EL, both fields are identical. Getters and setters are also identical (i've double-checked it). In fact, all the code for dateTo is a copy of dateFrom, that was changed in the editor after copying (replace all in selection).
Why does dateTo work but dateFrom doesn't ?
It turned out that the problem was not the date field, but the entered date (and a flaw in the dateConverter):
I've always tested the form using Jan 1st and Dec 31st of the same year.
Knowing that the browser-provided date input uses a date format depending on browser language rather than web site language, I've written a dateConverter that understands the most important formats, all of them with and without leading zeroes for one-digit values.
The flaw was that it's getAsString() returned a date format without leading zeroes, and the browser did not understand e.g. 2019-1-1.
Solution: Use a separate DateFormat that forces leading zeroes for getAsString() and return 2019-01-01.
Related
Dear friendly strangers,
using PrimeFaces 7.0 on JSF 2.2 I'm generating html-Code in my Bean and inject it in my xhtml with <h:outputText value="#{myBean.myHtml}" escape="false"/>. This naturally doesn't work with <p:.../> components, as they themselves generate/render actual html. The way I alter the data from my Database to get the final html is too complicated for html functions though, so I still wanna do it in my Java-Beans instead of using lots of ui:repeat and hypercomplex custom styles - even though I know this is not how jsf/PrimeFaces is meant to be used. Now checking the actual rendered html e.g. of a p:commandLink it gives
<a id="myContainerID:myComponentID" href="#" class="ui-commandlink ui-widget" onclick="PrimeFaces.ab({s:"myContainerID:myComponentID",f:"myContainerID"});return false;">myComponentValue</a>
,which I can generate easily, but the response-action called when receiving the component's Ajax request (s:"myContainerID:myComponentID") will be missing, which seems to be saved somewhere in the moment the actual html is generated with <p:...>.
Is there a way to manually set that response-action, if so how/where?
EDIT: Since (quoting PrimeFaces.ab function)
//ajax shortcut
ab: function(cfg, ext) {
return PrimeFaces.ajax.AjaxRequest(cfg, ext);
}
The PrimeFaces.ajax.AjaxRequest can be asynchronous or synchronous. The AjaxRequest uses the AjaxUtils, which handles all
send, process, response, and update.
PrimeFaces.ajax.AjaxRequest = function(cfg, ext) {
cfg.ext = ext;
if(cfg.async) {
return PrimeFaces.ajax.AjaxUtils.send(cfg);
}
else {
return PrimeFaces.ajax.Queue.offer(cfg);
} }
I suppose the answer, if there is any, should lay somewhere in AjaxUtils, but couldn't find it yet.
Thanks helluvalot for any suggestion/help.
EDIT 2: I did eventually manage to transcribe it all to the xhtml with nested ui:repeats and lots of custom styles, I'm still curious though whether there's a way to do it with in-Bean-generated html.
ExampleCode
myBean:
#ManagedBean(name = "myBean")
#SessionScoped
public class myBean {
private String html1;
private String html2;
#PostConstruct
public void init() {
html1 = "<p:commandLink id=\"myComponentID\" value=\"myComponentValue\" "
+ "action=\"#{someBean.doSomething()}\"";
html2 = "<a id=\"myContainerID:myComponentID\" "
+ "href=\"#\" class=\"ui-commandlink ui-widget\" "
+ "onclick=\"PrimeFaces.ab({s:\"myContainerID:myComponentID\","
+ "f:\"myContainerID\"});"
+ "return false;\">1. myComponentValue</a>";
}
public String getHtml1() {
return html1;
}
public void setHtml1(String html1) {
this.html1 = html1;
}
public String getHtml2() {
return html2;
}
public void setHtml2(String html2) {
this.html2 = html2;
}
}
myIndex.xhtml:
<h:html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
>
<h:head>
</h:head>
<h:body>
<h:form id="myContainerID">
<h:outputText value="#{myBean.html1}" escape="false" />
<h:outputText value="#{myBean.html2}" escape="false" />
</h:form>
</h:body>
</h:html>
This question already has an answer here:
Ajax update/render does not work on a component which has rendered attribute
(1 answer)
Closed 6 years ago.
I'm having a issue in PrimeFaces panel update.
I have one main panel which contains two output panel. Each output panel may contains one button which is swap panel. The swap panel button is used to swap the output panel from one to another.
If I update the button action for render the panels I need to provide the main panel Id it works fine. But for a tree structure hierarchy, If I mean to give the two output panel Ids It doesn't render the panel. The Button action called only once when I put the log to confirm that.
I will attach my code samples given below:
renderingPanel.XHTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>
Panel Rendered
</title>
</h:head>
<h:body>
<f:event listener="#{PanelRendered.initializePageAttributes}" type="preRenderComponent"/>
<h:form id="panelFormId">
<p:panel id="mainPanelId" widgetVar="mainPanelId">
<p:outputPanel id="mainOutputPanel" rendered="#{PanelRendered.mainPanelRendered}">
<h:outputText value="hello main"/>
<p:commandButton id="mainSwap" value="Swap To Sub Panel" update="mainOutputPanel,subOutputPanel" action="#{PanelRendered.mainButtonAction}" icon="ui-icon-transferthick-e-w"/>
</p:outputPanel>
<p:outputPanel id="subOutputPanel" rendered="#{PanelRendered.subPanelRendered}">
<h:outputText value="hello sub"/>
<p:commandButton id="subSwap" value="Swap To Main" update="subOutputPanel,mainOutputPanel" action="#{PanelRendered.subButtonAction}" icon="ui-icon-transferthick-e-w"/>
</p:outputPanel>
</p:panel>
</h:form>
</h:body>
</html>
PanelRendered.Java
public class PanelRendered
{
private boolean mainPanelRendered;
private boolean subPanelRendered;
private Logger logger = Logger.getLogger(PanelRendered.class);
public PanelRendered()
{
File configFile = new File("/home/nafeel/Applications/apache-tomcat-7.0.34/webapps/treetable/conf" + File.separator + "log4j.properties");
if (configFile.exists())
{
PropertyConfigurator.configure(configFile.getAbsolutePath());
}
else
{
System.out.println("Configuration Logger File not available");
}
}
public String mainButtonAction()
{
logger.info("Enter inside main button action");
mainPanelRendered = false;
subPanelRendered = true;
return null;
}
public String subButtonAction()
{
logger.info("Enter inside sub button action");
mainPanelRendered = true;
subPanelRendered = false;
return null;
}
public void initializePageAttributes()
{
logger.info("Enter inside initializepage");
mainPanelRendered = true;
subPanelRendered = false;
}
/**
* #return the mainPanelRendered
*/
public boolean isMainPanelRendered()
{
return mainPanelRendered;
}
/**
* #param mainPanelRendered the mainPanelRendered to set
*/
public void setMainPanelRendered(boolean mainPanelRendered)
{
this.mainPanelRendered = mainPanelRendered;
}
/**
* #return the subPanelRendered
*/
public boolean isSubPanelRendered()
{
return subPanelRendered;
}
/**
* #param subPanelRendered the subPanelRendered to set
*/
public void setSubPanelRendered(boolean subPanelRendered)
{
this.subPanelRendered = subPanelRendered;
}
}
Can you follow some guideline
JAVA code
Use proper naming for bean as your class name is PanelRendered and you are using the same name in xhtml file and you havent post your #ManagedBean #ViewScoped so i assume your bean name on xhtml should be panelRendered not PanelRendered.
Use #PostConstruct to initialize variable in JSF bean. avoid to use java constructor.
XHTML code:
I just change the bean name from PanelRendered to panelRendered and i am update panel like this update="mainPanelId"
And your code is working fine at my end, if you have any error please post here.
Your question
But for a tree structure hierarchy, If I mean to give the two output panel Ids It doesn't render the panel.
if the component with rendered="false" it is not generated any HTML code on browser, so you did not find the id="subOutputPanel" tag in your outputed HTML code, and when you click on command button it call the back bean method and come to update update="mainOutputPanel,subOutputPanel" it did not find the subOutputPanel id and ajax call will fail, and you will not get correct behavior or UI. and from next time it did not call any thing, for stop call back bean method you can study what happened after prime faces get ajax fail. hope this will help you.
I'm a bit of a n00b when it comes to JSF, but I have had similar issues. I think the Booleans in your PanelRendered class should have getters named as follows:
public boolean isMainPanelRendered()
public boolean isSubPanelRendered()
The expression language used in the XHTML file stays the same. It seems to be a convention that the expression language will add "is" to the front and capitalise the letter before searching the bean for the property(function or variable).
So this:
rendered="#{PanelRendered.mainPanelRendered}"
rendered="#{PanelRendered.subPanelRendered}"
stays the same.
Edited: added } at last of rendered.
Edited: realised it would need a getter for the private member variable
The p:menuBar and it's p:menuItems are generated at runtime. They render correctly and function perfectly with the exception that when any choice from the menu is clicked, nothing happens.
My index.xhtml is quite simple. It's just a p:tabView that composites my dataentry.xhtml in via a ui:include. The components on dataentry.xhtml are where the trouble is happening.
//dataentry.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:form id="dataEntryForm">
<p:menubar id="menuBar" binding="#{dataEntryBean.menuBar}" />
<p:dashboard id="dashboard" binding="#{dataEntryBean.dashboard}"/>
</h:form>
</ui:composition>
Here's the method that generates the p:menuBar. Again, all of this renders on the page correctly, it just doesn't do anything when you click on something.
private #NotNull Menubar spawnMenuBar() {
final MenuModel MODEL = new DefaultMenuModel();
{
final DefaultSubMenu SM = new DefaultSubMenu("Create New...", "ui-icon-circle-plus");
Arrays.stream(Type.values()).forEach(CT -> {
final String CT_ALT = CT.toInitialCaps();
final DefaultMenuItem DMI = new DefaultMenuItem(CT_ALT + " Card");
DMI.setId("createNew" + CT_ALT + "Type");
DMI.setParam("TYPE", CT.name());
DMI.setTitle("Creates a new " + CT_ALT + " type panel in the dashboard.");
DMI.setCommand("#{dataEntryBean.addNewTypePanel(param.get('TYPE'))}");
SM.addElement(DMI);
});
MODEL.addElement(SM);
}
{
final DefaultSubMenu SM = new DefaultSubMenu("Global Actions...", "ui-icon-alert");
// Implementation removed for brevity's sake...
MODEL.addElement(SM);
}
final Menubar MENU = new Menubar();
MENU.setModel(MODEL);
return MENU;
}
...and, finally, here's the method that all of those p:menuItems in the first p:subMenu are supposed to invoke.
public void addNewTypePanel(final String TYPE) {
System.out.println("Method Call: addNewTypePanel(" + TYPE + ")");
// Implementation removed for brevity's sake...
}
That println() in addNewTypePanel() never appears.
Bizarrely (and, I suspect, unrelated), the println() on the first line of this bean's constructor appears twice (and then a 3rd time when the appropriate tab in the p:tabView is loaded).
Any ideas?
doHope(HopeSeverity.VERY_HARD);
Edit #1: Based on Kukeltje's suggestion, I re-tested this code by commenting out the p:tabView entirely and copying the h:form from dataentry.xhmtl (see code block below). Unfortunately, the issue (issues?) were the same. Still no response on click, still see the bean's constructor being invoked three times.
// index.xhtml (alt version, same behavior)
<f:view>
<h:body>
<h3>Some Text</h3>
<h:form id="dataEntryForm">
<p:menubar id="menuBar" binding="#{dataEntryBean.menuBar}" />
<p:dashboard id="dashboard" binding="#{dataEntryBean.dashboard}"/>
</h:form>
</h:body>
</f:view>
For clarification, the bean is #SessionScoped and #ManagedBean. I am testing all of this on Tomcat 8.0.33 with MyFaces 2.2.10.
Edit #2: Based on Kukeltje's request, stripped out some information that doesn't appear to be involved in the issue.
In the following form, we try to return a user's input to JSF's h:inputText or PrimeFaces' p:inputText.
We experience strange behavior when non-Latin characters (Japanese, Hebrew, etc. ) are entered:
On first request we get unrecognized character set, but on the second request - we get a correct result.
Input/Output Examples (first run only):
Japanese:
input = 日
output = æ¥
Hebrew:
input = א
output = ×
JSF:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui">
<body>
<h:form>
<h:outputLabel value="Name:"/>
<h:inputText value="#{newTestController.registeredCustomerFirstName}"/>
<h:commandButton value="Continue" action="#{newTestController.RegisteredNewCustomer(actionEvent)}"/>
</h:form>
</body>
</html>
Backing Bean:
#ManagedBean(name = "newTestController")
#SessionScoped
public class NewTestController {
private String registeredCustomerFirstName;
public String getRegisteredCustomerFirstName() {
return registeredCustomerFirstName;
}
public void setRegisteredCustomerFirstName(String registeredCustomerFirstName) {
this.registeredCustomerFirstName = registeredCustomerFirstName;
}
public void RegisteredNewCustomer(ActionEvent actionEvent) throws Exception {
}
}
As commented above - it is needed to define a default-charset for the application server.
For glassfish: add <parameter-encoding default-charset="UTF-8" /> to glassfish-web.xml.
For other application servers see BalusC's blog regarding this issue.
This is related to < http://java.net/jira/browse/GLASSFISH-18007 >. That fix was made to prevent a warning message when we unconditionally set the encoding to UTF-8, which would seem to be what we want, but in this case we felt it safer to not do it.
I've created a related issue in Mojarra, < http://java.net/jira/browse/JAVASERVERFACES-2217 >. Bottom line: setting the encoding explicitly in the app configuration is the right solution. The implementation is already doing the right thing.
Specifying charset in the config file might be not enough.
Try using p:commandButton instead of h:commandButton. The p:commandButton by default uses ajax, while the h:commandButton does non-ajax submit.
I have two pages. Search page is the first page that takes user inputs. Second page shows the result set in datatable. Second page has 3 panel for resultset, update and create all in single page. Depending upon the which button being clicked, I am rendering panels true and false.
<h:panelGroup styleClass="panelGroup"
id="resultSet" rendered="#{bean.truefalse1}">
.
.
</h:panelGroup
<h:panelGroup styleClass="panelGroup"
id="updateForm" rendered="#{bean.truefalse2}">
.
.
</h:panelGroup
<h:panelGroup styleClass="panelGroup"
id="createForm" rendered="#{bean.truefalse3}">
.
.
</h:panelGroup>
From the search page I am setting these create and update panels to false and displaying only resultset.After the row from the result set is clicked I am showing
updateForm panel but keeping create panel to false.
But here the problem is, If there is validation error, then the property that was set from search page is being lost and all the panels are shown.
How do I get the value(boolean true or false) that was set from search page previously, since I am not navigating to different page.
I have getters and setters for boolean property in second class. I even tried keeping hidden fields(i.e the boolean property that was set from search page).
Shouldn't all the submitted values be recovered after validation error. Or just the ones we type in the form.
What is the best solution?
Any help is highly appreciated!!!
You indeed need to transfer the very same boolean properties to the next request. You can in theory use <h:inputHidden value="#{bean.boolean1}" /> for this, but unfortunately those will only be set during update model values phase, while you actually need it to be available during apply request values phase. Besides, they will also go lost when a validation error occurs.
There are three ways to fix this non-intuitive behaviour of h:inputHidden (I've ever filed a bug against it at the Mojarra issue list, but they didn't seem to do anything with it).
First is to use the binding on the h:inputHidden instead:
<h:inputHidden binding="#{bean.hidden1}" />
This however requires changes in the way you get/set the boolean values in the backing bean code. For example:
private HtmlInputHidden hidden1 = new HtmlInputHidden(); // +getter +setter.
public void setBoolean1(boolean boolean1) {
hidden1.setValue(boolean1);
}
public boolean getBoolean1() {
return (Boolean) hidden1.getValue();
}
Second is to use Tomahawk's t:saveState instead.
<t:saveState value="#{bean.boolean1}" />
The major advantage is that you don't need to change anything in the backing bean code. It will restore the value early before the apply request values phase. You only need to add extra libraries if not done yet, but as Tomahawk provides much more advantages than only the t:saveState, such as the in basic JSF implementation missing components/features t:inputFileUpload, t:dataList, t:dataTable preserveDataModel="true", t:selectOneRadio layout="spread" and so on, it is worth the effort.
The third way is to store them in a session scoped bean, but you actually don't want to do that for request scoped variables. It would only give "wtf?" experiences when the enduser has multiple tabs/windows open in the same session.
Edit: as per the comments, here's an SSCCE of the second way:
JSF page:
<%# taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%# taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<f:view>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<h:form id="form">
<h:inputHidden binding="#{myBean.hidden}" converter="javax.faces.Boolean" />
<h:commandButton value="submit" action="#{myBean.submit}"/>
<h:outputText value="Current boolean value: #{myBean.hidden.value}" />
</h:form>
</body>
</html>
</f:view>
MyBean class:
package mypackage;
import javax.faces.component.html.HtmlInputHidden;
public class MyBean {
private HtmlInputHidden hidden = new HtmlInputHidden();
public void submit() {
if (hidden.getValue() == null) {
hidden.setValue(true); // Set to true on 1st submit.
} else {
hidden.setValue(!((Boolean) hidden.getValue())); // Toggle true/false.
}
}
public HtmlInputHidden getHidden() {
return hidden;
}
public void setHidden(HtmlInputHidden hidden) {
this.hidden = hidden;
}
}
The relevant part of faces-config.xml:
<managed-bean>
<managed-bean-name>myBean</managed-bean-name>
<managed-bean-class>mypackage.MyBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Playground environment is JSF 1.2_13 on Tomcat 6.0.20.