SelectBooleanCheckbox rendered state does not match the backing bean - jsf-2

I'm using JSF2.0 and am building up a wizard. I have encountered a problem with SelectBooleanCheckboxes. Here is the workflow:
Load page with checkboxes (values are bound to a SortedMap in the backing bean).
Tick them, and click next. This increments a cursor, which the page uses to determine which PanelGroup the load.
The (correct) values are persisted to the bean.
Click back (cursor is decremented) and page renders the editable checkboxes. The first checkbox is not ticked (even though the bound variable holds a value of true for that box).
This cursor-based approach (which contains all of the wizard screens) doesn't seem to work. However, if i slightly modify this so that the prev/next buttons bring up different xhtml pages, this issue disappears.
Unfortunately I cant do this. We are going to plug this wizard into a modal dialog, so visiting a new page on prev/next will not work
I've written up a smallish example of this (rather than asking you to wade through the entire wizard).
Here is the Java class:
#ConversationScoped
#Named("hashBool")
public class HashBoolTest2 implements Serializable {
private static final long serialVersionUID = 1962031429874426411L;
#Inject private Conversation conversation;
private List<RestrictionItem> list;
private SortedMap<String, Boolean> values;
private int cursor;
public HashBoolTest2( ) {
List<String> none = new ArrayList<String>();
none.add("");
this.setList( new ArrayList< RestrictionItem >( ) );
this.getList().add( new RestrictionItem( "a", "a", none ) );
...
this.getList().add( new RestrictionItem( "e", "e", none ) );
this.setValues( new TreeMap< String, Boolean >() );
this.setCursor( 0 );
}
#PostConstruct
public void andThis() {
this.conversation.begin( );
}
// getters and setters for instance variables
#Override
public String toString() {
return "Values : " + this.values.toString( ) + " List: " + this.list.toString( );
}
public void kill() {
this.conversation.end( );
}
public void doNext(ActionEvent e) {
this.cursor++;
}
public void doPrev(ActionEvent e) {
this.cursor--;
}
}
Here is the XHTML fragment:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>IGNORED</title>
</head>
<body>
<ui:composition>
<h:panelGroup id="container">
<h:form>
<!-- edit state -->
<h:panelGroup id="edit" rendered="#{hashBool.cursor eq 0}">
<code>
<h:outputText value="#{hashBool.toString()}" escape="false"/>
</code>
<ul>
<ui:repeat value="#{hashBool.list}" var="elem">
<li>
<h:selectBooleanCheckbox id="elem" value="#{hashBool.values[elem.id]}" title="#{elem.displayName}" />
<h:outputLabel for="elem" value="#{elem.displayName}"/>
</li>
</ui:repeat>
</ul>
</h:panelGroup>
<!-- view state -->
<h:panelGroup id="view" rendered="#{hashBool.cursor eq 1}">
<code>
<h:outputText value="#{hashBool.toString()}" escape="false"/>
</code>
</h:panelGroup>
<br/>
<!-- buttons -->
<h:panelGroup id="buttons">
<f:ajax render=":container">
<h:commandButton value="Prev" actionListener="#{hashBool.doPrev}"/>
<h:commandButton value="Next" actionListener="#{hashBool.doNext}"/>
</f:ajax>
<h:commandButton value="Kill" actionListener="#{hashBool.kill()}"/>
</h:panelGroup>
</h:form>
</h:panelGroup>
</ui:composition>
</body>
</html>
Any suggestions are welcome! (And sorry if this is a double post, i havnt been able to uncover anything similar while searching here)

Mainly to ensure that the Wisdom of the Ancients remains properly documented (http://xkcd.com/979/): Turns out this is a bug within JSF 2.0.2 (which comes bundled with Liferay 6.0 GA 4). See here for more info: http://java.net/jira/browse/JAVASERVERFACES-1561

Related

How to iterate a HashMap with primefaces selectable datatable

I have tried different solutions but none is working in my case. I want all the rows in this datatable to be selectable. The problem seems to be the <ui:repeatthat is probably overriding the objects...
My bean:
#ManagedBean
#ViewScoped
public class Chat {
private static Map<String, List<ChatObject>> chat = new LinkedHashMap<String, List<ChatObject>>();
private ChatObject selectedChatObject;
public void onChatRowSelection(){
if(getSelectedChatObject() != null){
System.out.println("test");
}
}
public List<Map.Entry<String, List<ChatObject>>> getChatList() {
Set<Map.Entry<String, List<ChatObject>>> productSet = chat.entrySet();
return new ArrayList<Map.Entry<String, List<ChatObject>>>(productSet);
}
#PostConstruct
public void postConstructMethod() {
if(chat.isEmpty()){
List<ChatObject> objectsList1 = new ArrayList<ChatObject>();
objectsList1.add(new ChatObject("3369818", "1", "1"));
objectsList1.add(new ChatObject("3369819", "2", "2"));
objectsList1.add(new ChatObject("3369820", "3", "3"));
chat.put("Chat Topic 1", objectsList1);
List<ChatObject> objectsList2 = new ArrayList<ChatObject>();
objectsList2.add(new ChatObject("3369813", "4", "4"));
objectsList2.add(new ChatObject("3369815", "5", "5"));
chat.put("Chat Topic 2", objectsList2);
}
}
public ChatObject getSelectedChatObject() {
return selectedChatObject;
}
public void setSelectedChatObject(ChatObject selectedChatObject) {
this.selectedChatObject = selectedChatObject;
}
}
My JSF:
<!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:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<h:form id="form" enctype="multipart/form-data" acceptcharset="ISO-8859-1">
<ui:repeat value="#{chat.chatList}" var="chatEntry">
<h2><h:outputText value="#{chatEntry.key}" /></h2>
<br />
<p:dataTable
value="#{chatEntry.value}"
var="chatEntryVar"
widgetVar="chatTableWV"
styleClass="geralBorderless"
style="cursor:pointer"
rowKey="#{chatEntryVar.id}"
rendered="true"
selectionMode="single"
selection="#{chat.selectedChatObject}"
paginatorAlwaysVisible="false">
<p:ajax event="rowSelect"
listener="#{chat.onChatRowSelection}"
oncomplete="chatTableWV.unselectAllRows();">
</p:ajax>
<p:column>
<h:outputText value="#{chatEntryVar.name}" />
</p:column>
</p:dataTable>
</ui:repeat>
</h:form>
</html>
All the 5 ChatObject in my Map are successfully shown in my page. But onChatRowSelection method will only print "test" when I click in the rows related to the second list I added to my map: objectList2. When I click in the lines from the first list I added objectList1, when the system enters in the onChatRowSelection method, selectedChatObject will be null. How can I fix this?
Your problem is here:
<ui:repeat ...>
<p:dataTable ... widgetVar="chatTableWV">
<p:ajax ... oncomplete="chatTableWV.unselectAllRows();">
Multiple data tables are been assigned exactly the same widgetVar name in JavaScript scope. In effects, the following JavaScript code is generated:
window['chatTableWV'] = new Widget(tableElement1);
window['chatTableWV'] = new Widget(tableElement2);
window['chatTableWV'] = new Widget(tableElement3);
// ...
Basically, every iteration overrides the last object assigned to the declared widgetVar name until it ends up referencing the last one. All widgets expect of the last one are basically unavailable, causing them to not be functional anymore as to row selection.
Fix it accordingly by giving them each an unique widgetVar. You could use the iteration index of <ui:repeat> for this.
<ui:repeat ... varStatus="loop">
<p:dataTable ... widgetVar="chatTableWV_#{loop.index}">
<p:ajax ... oncomplete="chatTableWV_#{loop.index}.unselectAllRows();">
This way the following JavaScript code is generated:
window['chatTableWV_0'] = new Widget(tableElement1);
window['chatTableWV_1'] = new Widget(tableElement2);
window['chatTableWV_2'] = new Widget(tableElement3);
// ...
And finally PrimeFaces widget manager can find them all.

JSF Message on SUBMIT action

I begin with my case:
JSF 2.1
Tomcat 7.0.27
Netbeans as IDE
JSF and PRIMEFace (but optional)
Level JSF beginner
Level JAVA good and not god
I have done a simple JSF site to learn how to works with JSF. My question is based on Login example at this step the problem is not related about that login that is obviously insicure.
A bit of code:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
/**
*
* #author
*/
#ManagedBean
#SessionScoped
//#RequestScoped
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private final String userName = "User";
private final String userPassword = "12345";
private String name;
private String password;
private boolean isLogged=false;
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword( String password ) {
this.password = password;
}
public String login() {
if( !(userName==null || password==null)
&&
(userName.equals( name ) && userPassword.equals( password ))) {
isLogged=false;
return "main";
} else {
isLogged=true;
return "index";
}
}
public boolean getIsLogged(){
return isLogged;
}
}
The page index
<?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">
<h:head>
<title>TSAM 7.5 Login</title>
</h:head>
<h:body>
Login system
<br />
<!--<h:link outcome="welcomePrimefaces" value="Primefaces welcome page" />-->
<h:form>
User : <h:inputText value="#{user.name}" />
Password : <h:inputSecret value="#{user.password}" />
<h:commandButton action="#{user.login()}" value="Submit" />
<h:commandButton value="reset" type="reset" />
<h:commandButton value="otherpage" action="otherpage"></h:commandButton>
</h:form>
</h:body>
</html>
The main page
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<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:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<f:event type="preRenderView" listener="#{user.isLogged}"/>
<f:view contentType="text/html">
<h:head>
<f:facet name="first">
<meta content='text/html; charset=UTF-8' http-equiv="Content-Type"/>
<title>PrimeFaces</title>
</f:facet>
</h:head>
<h:body>
<p:layout fullPage="true">
<p:layoutUnit position="north" size="100" resizable="true" closable="true" collapsible="true">
Header
</p:layoutUnit>
<p:layoutUnit position="south" size="100" closable="true" collapsible="true">
Footer
</p:layoutUnit>
<p:layoutUnit position="west" size="175" header="Left" collapsible="true">
<p:menu>
<p:submenu label="Resources">
<p:menuitem value="Demo" url="http://www.primefaces.org/showcase-labs/ui/home.jsf" />
<p:menuitem value="Documentation" url="http://www.primefaces.org/documentation.html" />
<p:menuitem value="Forum" url="http://forum.primefaces.org/" />
<p:menuitem value="Themes" url="http://www.primefaces.org/themes.html" />
</p:submenu>
</p:menu>
</p:layoutUnit>
<p:layoutUnit position="center">
Welcome to PrimeFaces
</p:layoutUnit>
</p:layout>
</h:body>
</f:view>
</html>
First
I use action="#{user.login()}" to make navigation action is this correct or there is a better pattern?
But the real question is: How to show a message If I redirect?
I like to show a message I know the example by PrimeFace http://www.primefaces.org/showcase/ui/dialogLogin.jsf. but it doesn't redirect or show anything.
But if i use only "plain" JSW without PrimeFace, i like to put a
because it is similar to PrimeFaces so switch is simple.
I'd like to adopt a "pattern" so i can reuse it for eg when i do a serch an no data is present, or when i call "erease DB" and application say work in progress an then say OK all bank account are esreased (Only an example!! but interesting because there are 2 message).
Thanks
I try
public String login() {
if (!(userName == null || password == null)
&& (userName.equals( name ) && userPassword.equals( password ))) {
isLogged = true;
return "main";
} else {
isLogged = false;
FacesMessage facesMsg;
facesMsg = new FacesMessage( FacesMessage.SEVERITY_ERROR, "No login", "No login because username or passsword are incorrect etc" );
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage( "loginError", facesMsg );
return "index";
}
}
And edited the page
<h:body>
Login system
<br />
<!--<h:link outcome="welcomePrimefaces" value="Primefaces welcome page" />-->
<h:form>
User : <h:inputText value="#{user.name}" />
Password : <h:inputSecret value="#{user.password}" />
<h:commandButton action="#{user.login()}" value="Submit" />
<h:commandButton value="reset" type="reset" />
<h:commandButton value="Cambio Password" action="changePassword"></h:commandButton>
</h:form>
<h:message for="" style="color:red;margin:8px;"/>
</h:body>
It works but it's not ok because it's not ok to put a string in the bean. And I need the multilanguage this string has to generated by the beans.... mmm this is not OK something i'm missing.
There's extremely a lot of noise in the question. I understand that your question ultimately boils down to:
How do I create a localized faces message in bean action method?
In that case, just get the message from the current resource bundle yourself.
As you're talking about localization, you should surely already have something like as
<resource-bundle>
<base-name>com.example.i18n.text</base-name>
<var>text</var>
</resource-bundle>
in your faces-config.xml. You could just get it in the bean as well with help of ResourceBundle which JSF itself is actually also using under the covers
Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
ResourceBundle text = ResourceBundle.getBundle("com.example.i18n.text", locale);
This way you could compose your message as
String summary = text.getString("messages.no_login_summary");
String detail = text.getString("messages.no_login_detail");
new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, detail);

Form doesn't submit values when commandLink is used instead of commandButton

I made following jsf page. In my Managed Bean i want evaluate the input,
but i dont get the values.
If i press my commandLink i dont get any values. when i use a commandButton it works:
<?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:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<ui:composition template="../templates/common.xhtml">
<ui:define name="pageTitle">Test</ui:define>
<ui:define name="pageHeader">Test</ui:define>
<ui:define name="body">
<h:panelGroup id="messagePanel" layout="block">
<h:messages errorStyle="color: red" infoStyle="color: green"
layout="table" />
</h:panelGroup>
<h:form>
<h:outputLabel value="#{bundle.SearchAdressLabel_name}"
for="axname" />
<h:inputText id="axname"
value="#tbaxController.name}"
title="#{bundle.SearchAdressTitle_name}" />
</h:panelGrid>
<br />
<br />
<h:commandButton id="submit" value="#{bundle.SearchAdressLabel_cmdsearch}" action="#{tbaxController.prepareList}">
</h:commandButton>
<h:commandLink action="#{tbaxController.prepareList}"
value="#{bundle.SearchAdressLabel_cmdsearch}" immediate="true" />
<br />
<br />
<h:commandLink value="#{bundle.SearchAdressLabel_cmdclear}"
type="reset" />
</h:form>
</ui:define>
</ui:composition>
</html>
Here is a part of my MB:
#ManagedBean(name = "tbaxController")
#SessionScoped
public class tbaxController implements Serializable {
private static final long serialVersionUID = 1L;
private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger
.getLogger(tbaxController.class);
private Tbax current;
private DataModel items = null;
#EJB
private TbaxFacade ejbFacade;
private PaginationHelper pagination;
private int selectedItemIndex;
private String name;
public tbaxController() {
}
public String getname() {
// Get the field
return searchAxart;
}
public void setname(String oname) {
// Set the field this.searchAxart
this.name = oname.trim();
}
...
public String prepareList() {
logger.info("prepareList:" + name); **//null with commandLink!
recreateModel();
return "ADList";
}
...
Why does my prepareList method doesn't get any values with a commandLink?
The immediate="true" makes jsf to step over the process validation and update model phases. It jump directly to invoke application phase. That's why you don't get any values on the model. Try removing it and see what happens.

f:validateRequiered doesn't work as expected

I have just created a NetBeans project with JSF 2.0 and I have a problem with f:validateRequired. The bean
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class TestBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String action() {
return "test";
}
}
and the page
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Test</title>
<h:outputStylesheet name="css/stylesheet.css" />
</h:head>
<h:body>
<h:form>
<div id="content">
Value:
<h:message for="test" />
<h:inputText value="#{testBean.value}" id="test">
<f:validateRequired />
</h:inputText>
<br/>
<h:commandButton action="#{testBean.action}" value="Action" />
</div>
</h:form>
</h:body>
</html>
seems to be allright, but the h:message isn't there until I supply the requered="true" attribute on the inputText. What I am missing? Why the validation does not occure whithout the requered="true" attribute?
I figured the answer: fields with empty input are not validated at all by default. If you wish to validate such field you have to set required=true. See UIInput.validateValue() JavaDoc
You can enable the validation of empty fields by setting the javax.faces.VALIDATE_EMPTY_FIELDS context parameter to true. See JavaDoc. After doing that the example above works as expected.
I know this post is kind of old, but I'm using MyFaces and apparently javax.faces.VALIDATE_EMPTY_FIELDS is set to false by default.

When adding a faces message in JSF my actions aren't performed?

I have the following backing bean:
#ViewScoped
#ManagedBean
public class WeighFamilyBacking2 implements Serializable {
private static final long serialVersionUID = 1L;
private String[] children = new String[] { "Child1", "Child2", "Child3" };
private HashMap<String, Integer> newWeights;
public WeighFamilyBacking2() {
newWeights = new HashMap<String, Integer>();
for (String s : getChildren())
newWeights.put(s, new Integer(0));
}
public void distributeWeightsWithoutMessage(ActionEvent event) {
for (String s : newWeights.keySet()) {
newWeights.put(s, newWeights.get(s) + 1);
}
}
public void distributeWeights(ActionEvent event) {
for (String s : newWeights.keySet()) {
newWeights.put(s, newWeights.get(s) + 1);
}
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Succesful", "Weights redistributed."));
}
public HashMap<String, Integer> getNewWeights() {
return newWeights;
}
public List<String> getChildren() {
return Arrays.asList(children);
}
}
... And the following xhtml page:
<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<h:body>
<h:form>
<ui:repeat var="child" value="#{weighFamilyBacking2.children}">
<h:outputText value="#{child}" />
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:inputText id="oz" value="#{weighFamilyBacking2.newWeights[child]}" />
<h:inputText id="lbs"
value="#{weighFamilyBacking2.newWeights[child]}" />
<br />
</ui:repeat>
<h:commandButton
actionListener="#{weighFamilyBacking2.distributeWeights}"
value="Redistribute" />
<h:commandButton
actionListener="#{weighFamilyBacking2.distributeWeightsWithoutMessage}"
value="Redistribute Without Message" />
</h:form>
</h:body>
</html>
This is a simple reproducible test case. When you click on the redistribute without message, things work as expected. When you click on the redistribute button it displays the success message but the input fields are not updated. However, the text output field is updated just one time.
I have tried using immediate=true on both buttons and that doesn't affect this. This is a very simple case, I can't understand why it doesn't work.
I have tried this with all recent versions of Mojarra including 2.1.3.
This is another <ui:repeat> anomaly. I haven't nail down the exact root cause yet so that I can check if this is already reported to the JSF guys and if necessary report it, but I can tell that it works when I replace the <ui:repeat> by a <h:dataTable>.
<h:dataTable var="child" value="#{weighFamilyBacking2.children}">
<h:column>
<h:outputText value="#{child}" />
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:outputText value="#{weighFamilyBacking2.newWeights[child]}" /> -
<h:inputText id="oz" value="#{weighFamilyBacking2.newWeights[child]}" />
<h:inputText id="lbs"
value="#{weighFamilyBacking2.newWeights[child]}" />
</h:column>
</h:dataTable>
Maybe a <table> is not semantically correct for you. If this is really undesireable, you might want to check if it works without problems with Tomahawk's <t:dataList>, RichFaces' <rich:dataList>, PrimeFaces' <p:dataList>, etc each which supports rendering the children without additional markup.
Update: I reported it as issue 2157.

Resources