Due to UI layout issue, I have to separate inputs into multiple form. How to submit JSF ajax with inputs from multiple forms?
Based on sample code below, how to get form1 input1 value when click on the Ajax Call button in form2?
Weblogic 12.2 Java 8 Servlet 3.1 JSF 2.2 CDI 1.1 EJB 3.2
JSF Page
<!DOCTYPE HTML>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:jsf="http://xmlns.jcp.org/jsf"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions">
<h:head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0" />
<title>Ajax Test</title>
</h:head>
<h:body>
<ui:debug hotkey="x" />
<h:messages id="msg" />
<fieldset>
<legend>Form 1</legend>
<h:form
id="form1"
method="get">
<h:inputText
id="input1"
value="#{ajaxTestBean.input1}" />
<h:commandButton
value="Standard call"
action="#{ajaxTestBean.call}" />
</h:form>
</fieldset>
<fieldset>
<legend>Form 2</legend>
<h:form
id="form2"
method="get">
<h:inputText
id="input2"
value="#{ajaxTestBean.input2}" />
<h:commandButton value="Ajax Call">
<f:ajax
execute="form1:input1 form2:input2"
render="msg form1:input1 form2:input2"
listener="#{ajaxTestBean.callAjax}" />
</h:commandButton>
</h:form>
</fieldset>
</h:body>
</html>
Java Class
package dev;
import javax.faces.event.AjaxBehaviorEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#javax.inject.Named("ajaxTestBean")
#javax.faces.view.ViewScoped
public class AjaxTestBean implements java.io.Serializable {
static final long serialVersionUID = 1L;
static final Logger logger = LogManager.getLogger();
String input1;
String input2;
public AjaxTestBean() {
}
public void call() {
logger.traceEntry();
logger.debug("input1: {}", this.input1);
logger.debug("input2: {}", this.input2);
logger.traceExit();
}
public void callAjax(AjaxBehaviorEvent event) {
logger.traceEntry();
logger.debug("input1: {}", this.input1);
logger.debug("input2: {}", this.input2);
logger.traceExit();
}
public String getInput1() {
return input1;
}
public void setInput1(String input1) {
this.input1 = input1;
}
public String getInput2() {
return input2;
}
public void setInput2(String input2) {
this.input2 = input2;
}
}
I'm sure that the question is asked before, but I can't fin my explicit problem, I'm afraid it is only a little typo and I can't see it.
I have a simple page in primefaces 10 with a toolbar, with an add-button, a table and a dialoge for adding the data. The dialog has a rendered tag that the requiered field are only rendered if there is a new variable. Everything I used on several other pages of my project.
The new Variable is initialized perfectly but the inside of the dialog isn't rendered, if I remove the rendered tag the field is rendered, but I have put some test-content into my new Variable and this isn't shown either, so I think that my update doesn't get called but I don't see why.
So here is my code:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
template="layout.xhtml">
<ui:define name="header">
<div id="header">
ChangeLog
</div>
</ui:define>
<ui:define name="main">
<h:form id="changelogfrm">
<p:growl id="messages" showDetail="true" life="3000" />
<div class="card">
<p:toolbar>
<p:toolbarGroup>
<p:commandButton value="Neu" icon="pi pi-plus" actionListener="#{changeloghandler.newChangelog}"
update=":changelogfrm:manage-change-content" oncomplete="PF('manageChangeDialog').show()"
styleClass="ui-button-success" style="margin-right: .5rem" />
</p:toolbarGroup>
</p:toolbar>
<p:dataTable var="change" value="#{changeloghandler.changeLogs}"
showGridlines="true" size="small" id="dtChange">
<p:column headerText="Version">
<h:outputText value="#{change.version}" />
</p:column>
<p:column headerText="Typ">
<h:outputText value="#{change.changeType}"/>
</p:column>
<p:column headerText="Beschreibung">
<h:outputText value="#{change.description}"/>
</p:column>
<p:column headerText="Datum">
<h:outputText value="#{change.date}">
<f:convertDateTime type="date" pattern="dd.MM.yyyy HH:mm"/>
</h:outputText>
</p:column>
</p:dataTable>
<p:dialog header="Change" showEffect="fade" modal="true"
widgetVar="manageChangeDialog" responsive="true">
<p:outputPanel id="manage-change-content" class="ui-fluid">
<p:outputPanel rendered="#{not empty changeloghandler.selected}">
<div class="p-field">
<p:outputLabel for="chBeschreibung">Beschreibung</p:outputLabel>
<p:inputTextarea id="chBeschreibung" value="#{changeloghandler.selected.description}" required="true"/>
</div>
</p:outputPanel>
</p:outputPanel>
<f:facet name="footer">
<p:commandButton value="Save" icon="pi pi-check" actionListener="#{changeloghandler.save}"
update="manage-change-content" process="manage-change-content #this"/>
<p:commandButton value="Cancel" icon="pi pi-times" onclick="PF('manageChangeDialog').hide()"
class="ui-button-secondary"/>
</f:facet>
</p:dialog>
</div>
</h:form>
</ui:define>
</ui:composition>
The save-function in the dialog isn't called either.
I've also checked the html on the site, there is no double-form and the ids are set correctly.
Hope you can help me.
!!!EDIT!!!
Hi, here you have the Bean-Class:
package main.java.handler;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import org.primefaces.PrimeFaces;
import main.java.persistence.entities.ChangeLog;
import main.java.persistence.entities.enums.ChangeType;
import main.java.persistence.entities.enums.Version;
import main.java.persistence.interfaces.ChangeLogDbInterface;
#Named("changeloghandler")
#SessionScoped
public class ChangeLogHandler implements Serializable{
private static final long serialVersionUID = 1L;
private List<ChangeLog> changeLogs;
private ChangeLog selected;
private List<Version> versions;
private ChangeType[] changeTypes;
#PostConstruct
private void init() {
changeLogs = ChangeLogDbInterface.loadChangeLogItems();
versions = new ArrayList<>();
for(Version v : Version.values()) {
if(v.isActive()) versions.add(v);
}
changeTypes = ChangeType.values();
}
public void newChangelog() {
ChangeLog newLog = new ChangeLog();
newLog.setDate(new Timestamp(System.currentTimeMillis()));
this.selected = newLog;
}
public void save() {
if (this.selected.getId() == 0) {
ChangeLogDbInterface.createChangeLogItem(selected);
this.changeLogs.add(this.selected);
}
else {
ChangeLogDbInterface.updateChangeLogItem(selected);
}
PrimeFaces.current().executeScript("PF('manageChangeDialog').hide()");
PrimeFaces.current().ajax().update("changelogfrm:dtChange");
}
public List<ChangeLog> getChangeLogs() { return changeLogs; }
public ChangeLog getSelected() { return selected; }
public List<Version> getVersions() { return versions; }
public ChangeType[] getChangeTypes() { return changeTypes; }
public void setChangeLogs(List<ChangeLog> changeLogs) { this.changeLogs = changeLogs; }
public void setSelected(ChangeLog selected) { this.selected = selected; }
public void setVersions(List<Version> versions) { this.versions = versions; }
public void setChangeTypes(ChangeType[] changeTypes) { this.changeTypes = changeTypes; }
}
!!! EDIT 2 !!!
Here is the template, but I think that doesn't help much either:
<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:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Asset Tool Connector</title>
<link type="text/css"
href="${facesContext.externalContext.requestContextPath}/resources/css/style.css"
rel="stylesheet" />
<link type="image/x-icon"
href="${facesContext.externalContext.requestContextPath}/resources/images/netzwerk.png"
rel="shortcut icon" />
</h:head>
<h:body>
<ui:insert name="header"/>
<f:event listener="#{sessionHandler.checkLoggedIn}" type="preRenderView" />
<div id="menu">
<ui:include src="menu.xhtml" />
</div>
<div id="main">
<ui:insert name="main"/>
</div>
<div id="footer">
<div>
<h:form id="footerForm">
<p:commandButton value="ChangeLog" action="/changelog?faces-redirect=true"/>
</h:form>
</div>
© ATC - by 5332
</div>
</h:body>
</html>
Except the button in the footer links to the page with my issue, if that would be an issue.
I'm currently trying to implement a dynamic survey page containing pages, sections and questions defined by the user (part of a larger application).
The user may defined different question types, which will render a different component (radio, textarea, textfield, selectionlist, ...).
This app is currently deployed in Wildfly 16 / Java 8 / JSF 2.3 / Servlet 4.
Since the user may define a specific set of values and associated images for the radio button, I need to customize the radio button output. So my option was to use the new group attribute available in selectoneradio.
Using this new attribute is causing erratic behaviour when used inside a multi-level ui:repeat.
The following example was simplified and created in order to illustrate the problem.
Class
package test;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
#Named("test")
#ViewScoped
public class Test implements Serializable
{
private static final long serialVersionUID = 1L;
private static Map<String, Map<String, String>> questionMap = new TreeMap<>();
private static Map<String, String> fixedValuesMap = new TreeMap<>();
private Map<String, String> answerMap = new TreeMap<>();
private List<String> sections = Arrays.asList("Section_1", "Section_2", "Section_3", "Section_4");
static
{
fixedValuesMap.put("1", "Value 1");
fixedValuesMap.put("2", "Value 2");
fixedValuesMap.put("3", "Value 3");
fixedValuesMap.put("4", "Value 4");
fixedValuesMap.put("5", "Value 5");
Map<String, String> sec1questions = new TreeMap<>();
sec1questions.put("1", "Question 1");
sec1questions.put("2", "Question 2");
sec1questions.put("3", "Question 3");
questionMap.put("Section_1", sec1questions);
Map<String, String> sec2questions = new TreeMap<>();
sec2questions.put("4", "Question 4");
questionMap.put("Section_2", sec2questions);
Map<String, String> sec3questions = new TreeMap<>();
sec3questions.put("5", "Question 5");
questionMap.put("Section_3", sec3questions);
Map<String, String> sec4questions = new TreeMap<>();
sec4questions.put("6", "Question 6");
questionMap.put("Section_4", sec4questions);
}
public Test()
{
}
#PostConstruct
private void init()
{
answerMap.put("1", null);
answerMap.put("2", null);
answerMap.put("3", null);
answerMap.put("4", null);
answerMap.put("5", null);
answerMap.put("6", null);
}
public String getQuestionType(String index)
{
switch(index)
{
case "1":
return "RADIO_BUTTON";
case "2":
return "RADIO_BUTTON";
case "3":
return "RADIO_BUTTON";
case "4":
return "TEXT_AREA";
case "5":
return "RADIO_BUTTON";
case "6":
return "FREE_TEXT";
default:
return "FREE_TEXT";
}
}
public Map<String, String> getQuestions(String section)
{
return questionMap.get(section);
}
public Map<String, String> getAnswerMap()
{
return answerMap;
}
public Map<String, String> getFixedValues()
{
return fixedValuesMap;
}
public List<String> getSections()
{
return sections;
}
public void changeRadio(String questionKey, String questionValue)
{
answerMap.put(questionKey, questionValue);
}
public String submit()
{
for(Map.Entry<String, String> entry : answerMap.entrySet())
System.out.println("ENTRY: " + entry.getKey() + " - " + entry.getValue());
return null;
}
}
XHTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
<h:head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<meta name="description" content="My Test"/>
<link rel="stylesheet" href="#{request.contextPath}/resources/bootstrap/css/bootstrap.min.css" />
<title>My Test</title>
</h:head>
<h:body>
<div class="container-fluid">
<div class="row">
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">UI Repeat Test</h1>
</div>
<h:form role="form" prependId="false">
<div class="row mx-2">
<ui:repeat var="sec" value="#{test.sections}">
<div class="col-12">
<ui:repeat var="question" value="#{test.getQuestions(sec)}">
<div>
<div class="col-12">
<div class="form-group">
<label for="answer">#{question.key} - #{question.value}</label>
<div class="col-12">
<h:panelGroup rendered="#{test.getQuestionType(question.key) eq 'FREE_TEXT'}" layout="block">
<h:inputText value="#{test.answerMap[question.key]}" styleClass="form-control"/>
</h:panelGroup>
<h:panelGroup rendered="#{test.getQuestionType(question.key) eq 'TEXT_AREA'}" layout="block">
<h:inputTextarea value="#{test.answerMap[question.key]}" styleClass="form-control" rows="2" />
</h:panelGroup>
<h:panelGroup rendered="#{test.getQuestionType(question.key) eq 'RADIO_BUTTON'}" layout="block">
<table class="radio-label checkbox">
<tbody>
<tr>
<ui:repeat var="item" value="#{test.fixedValues.entrySet()}">
<td class="text-center grid-margin">
<h:selectOneRadio group="#{question.key}" value="#{test.answerMap[question.key]}" layout="lineDirection" styleClass="checkbox" >
<f:selectItem itemValue="#{item.key}" itemLabel="#{item.value}" />
</h:selectOneRadio>
</td>
</ui:repeat>
</tr>
</tbody>
</table>
</h:panelGroup>
</div>
</div>
</div>
</div>
</ui:repeat>
</div>
</ui:repeat>
</div>
<div class="row mx-2 my-2">
<div class="col-12">
<h:commandButton value="Test Me" type="submit" action="#{test.submit}" styleClass="btn btn-primary" />
</div>
</div>
</h:form>
</main>
</div>
</div>
<script src="#{request.contextPath}/resources/jquery/jquery.slim.min.js"></script>
<script src="#{request.contextPath}/resources/bootstrap/js/bootstrap.bundle.min.js"></script>
</h:body>
</html>
When the form is submitted only the last radio button and text field values are stored.
If I replace the selectItems ui:repeat
<table class="radio-label checkbox">
<tbody>
<tr>
<ui:repeat var="item" value="#{test.fixedValues.entrySet()}">
<td class="text-center grid-margin">
<h:selectOneRadio group="#{question.key}" value="#{test.answerMap[question.key]}" layout="lineDirection" styleClass="checkbox" >
<f:selectItem itemValue="#{item.key}" itemLabel="#{item.value}" />
</h:selectOneRadio>
</td>
</ui:repeat>
</tr>
</tbody>
</table>
with
<h:selectOneRadio value="#{test.answerMap[question.key]}" layout="lineDirection" >
<f:selectItems value="#{test.fixedValues.entrySet()}" var="item" itemLabel="#{item.key}" itemValue="#{item.value}" />
</h:selectOneRadio>
everything works fine.
I really need to use the first option, so I can add some images to the radio button values.
Am I missing something?
It seemes like you have found an issue. I tried to simplify the example as follows:
My managed Bean:
package my.pkg;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
#Named
#RequestScoped
public class MyBean {
private List<String> items;
private List<Number> numbers;
private Map<String, Object> mapVal;
#PostConstruct
public void init() {
mapVal = new LinkedHashMap<>();
items = new ArrayList<>();
numbers = new ArrayList<>();
for (int i = 0; i < 3; i++) {
items.add("group_" + i);
numbers.add(i);
}
}
// getters/setters ...
}
Example form:
<!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:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<h:head />
<h:body>
<h:form id="frm1">
<ui:repeat var="grp" value="#{myBean.items}">
<ui:repeat var="num" value="#{myBean.numbers}" varStatus="stat">
<h:selectOneRadio id="radioButton" value="#{myBean.mapVal[grp]}"
group="myGroup_#{grp}">
<f:selectItem itemValue="#{num}" itemLabel="#{grp}: #{num}" />
</h:selectOneRadio>
<br />
</ui:repeat>
<hr />
</ui:repeat>
<h:commandButton value="submit" />
<h:outputText value="myBean.mapVal: #{myBean.mapVal}" />
</h:form>
</h:body>
</html>
User interface an example input:
After submission I'd expect output to be:
myBean.mapVal: {group_0=0, group_1=1, group_2=2}
But it is:
myBean.mapVal: {group_2=2}
The radio buttons from group 0 and 1 lose their selection.
For some inputs I get the expected results:
myBean.mapVal: {group_0=0, group_1=0, group_2=0}
myBean.mapVal: {group_0=1, group_1=1, group_2=1}
myBean.mapVal: {group_0=2, group_1=2, group_2=2}
... using Mojarra 2.3.9.
For MyFaces 2.3.4 I get the expected result for the selection in above screenshot:
{group_0=0, group_1=1, group_2=2}
but it fails for other selections:
1)
expected: {group_0=0, group_1=0, group_2=0}
but is: {group_2=0}
2)
expected: {group_0=0, group_1=0, group_2=2}
but is: {group_1=0, group_2=2}
3)
expected: {group_0=1, group_1=1, group_2=0}
but is: {group_1=1, group_2=0}
In my opinion we should reportan issue for Mojarra and ( if not already present) for MyFaces.
Workaround
If I replace
<ui:repeat var="grp" value="#{myBean.items}">
by
<c:forEach var="grp" items="#{myBean.items}">
I get the expected results for Mojarra and MyFaces.
Like #Selaron suggested, I created an issue under eclipse-ee4j/mojarra
Thank you for the help!
I'm struggling with letting JSF execute the action behind a commandLink. It doesn't seem to execute its action even though it's not in a form that's nested in another form, there shouldn't be any validation errors and the element seems to be rendered properly.
The page is shows details for a flight booking. The button I'm talking about should take a user to a payment page.
The trouble happens all the way in the back of the form in this file (the messages above don't print anything):
<ui:composition template="/WEB-INF/template.xhtml">
<ui:define name="metaData">
<f:metadata>
<f:viewParam name="departureId" value="#{bookingCreationWizard.departureId}"/>
<f:viewParam name="returnId" value="#{bookingCreationWizard.returnId}"/>
</f:metadata>
</ui:define>
<ui:define name="pageTitle">#{msg.flights_details_page_title}</ui:define>
<ui:define name="pageContent">
<h1>#{msg.flights_details_page_title}</h1>
<h:panelGroup layout="block">
<h2>#{msg.flight_details_h2_departure}</h2>
<table>
<tr>
<th>Airline</th>
<th>Class</th>
<th>Seats Remaining</th>
<th>Departure Time</th>
<th>Flight Duration</th>
<th>Arrival Time</th>
<th>Departure Airport</th>
<th>Arrival Airport</th>
<th>Price</th>
</tr>
<tr>
<td>#{bookingCreationWizard.departureFlight.flight.airline.name}</td>
<td>#{bookingCreationWizard.departureFlight.name}</td>
<td>#{bookingCreationWizard.departureFlight.freeSeats}</td>
<td>#{bookingCreationWizard.departureFlight.flight.departureTime}</td>
<td>TODO</td>
<td>#{bookingCreationWizard.departureFlight.flight.arrivalTime}</td>
<td>#{bookingCreationWizard.departureFlight.flight.departureAirport.code}</td>
<td>#{bookingCreationWizard.departureFlight.flight.arrivalAirport.code}</td>
<td>#{bookingCreationWizard.departureFlight.price}</td>
</tr>
</table>
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{bookingCreationWizard.hasReturnFlight()}">
<h2>#{msg.flight_details_h2_return_flight}</h2>
<table>
<tr>
<th>Airline</th>
<th>Class</th>
<th>Seats Remaining</th>
<th>Departure Time</th>
<th>Flight Duration</th>
<th>Arrival Time</th>
<th>Departure Airport</th>
<th>Arrival Airport</th>
<th>Price</th>
</tr>
<tr>
<td>#{bookingCreationWizard.returnFlight.flight.airline.name}</td>
<td>#{bookingCreationWizard.returnFlight.name}</td>
<td>#{bookingCreationWizard.returnFlight.freeSeats}</td>
<td>#{bookingCreationWizard.returnFlight.flight.departureTime}</td>
<td>TODO</td>
<td>#{bookingCreationWizard.returnFlight.flight.arrivalTime}</td>
<td>#{bookingCreationWizard.returnFlight.flight.departureAirport.code}</td>
<td>#{bookingCreationWizard.returnFlight.flight.arrivalAirport.code}</td>
<td>#{bookingCreationWizard.returnFlight.price}</td>
</tr>
</table>
</h:panelGroup>
<h:panelGroup layout="block">
<h2>#{msg.flight_details_h2_price}</h2>
<table>
<tr>
<th>#{msg.flight_details_price_table_flight}</th>
<th>#{msg.flight_details_price_table_amount}</th>
<th>#{msg.flight_details_price_table_total_price}</th>
</tr>
<tr>
<td>#{bookingCreationWizard.departureFlight.flight.departureAirport.code} - #{bookingCreationWizard.departureFlight.flight.arrivalAirport.code}</td>
<td>#{bookingCreationWizard.numberOfPeople}</td>
<td>#{bookingCreationWizard.departureFlight.finalPrice}</td>
</tr>
<h:panelGroup rendered="#{bookingCreationWizard.hasReturnFlight()}">
<td>#{bookingCreationWizard.returnFlight.flight.departureAirport.code} - #{bookingCreationWizard.returnFlight.flight.arrivalAirport.code}</td>
<td>#{bookingCreationWizard.numberOfPeople}</td>
<td>#{bookingCreationWizard.returnFlight.finalPrice}</td>
</h:panelGroup>
</table>
</h:panelGroup>
<h:panelGroup layout="block">
<h:form>
<h:messages style="color:red;margin:8px;"/>
<h:commandLink action="#{bookingCreationWizard.proceedToPayment()}" value="#{msg.flight_details_booking_button}" />
</h:form>
</h:panelGroup>
</ui:define>
</ui:composition>
</html>
Below I've also included the template this file is embedded in, and the #Conversationscoped bean that contains the action that should be executed.
Template:
<?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://xmlns.jcp.org/jsf/html"
xmlns:f="http://java.sun.com/jsf/core" xml:lang="en" lang="en"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<f:view locale="#{languageSwitcherController.locale}">
<h:head>
<title><ui:insert name="pageTitle">#{msg.template_title_addon}</ui:insert></title>
<h:outputStylesheet library="css" name="normalize.css"/>
<h:outputStylesheet library="css" name="skeleton.css"/>
<h:outputStylesheet library="css" name="main.css"/>
<ui:insert name="metaData"/>
<meta name="viewport" content="width=device-width, inital-scale=1.0"/>
</h:head>
<h:body>
<h:form id="langauge_form">
<h:commandLink action="#{languageSwitcherController.changeLanguage('nl_BE')}" value="Nederlands"/> |
<h:commandLink action="#{languageSwitcherController.changeLanguage('en')}" value="English"/>
</h:form>
<!--<h:graphicImage name="01.jpg" library="images" width="500" height="100"/>-->
<h1>#{msg.template_header}</h1>
<div>
<ui:insert name="pageContent">
</ui:insert>
</div>
<br/>
#{msg.template_footer}
</h:body>
</f:view>
</html>
Bean:
#ConversationScoped
#Named
public class BookingCreationWizard implements Serializable {
#Inject
private Conversation conversation;
#Inject
private CategoryService service;
private Long departureId;
private Long returnId;
private Category departureFlight;
private Category returnFlight;
private int numberOfPeople;
#PostConstruct
public void init() {
this.numberOfPeople = 1;
}
public int getNumberOfPeople() {
return this.numberOfPeople;
}
public void setNumberOfPeople(int numberOfPeople) {
if (conversation.isTransient()){
conversation.begin();
}
this.numberOfPeople = numberOfPeople;
}
public Long getDepartureId() {
return departureId;
}
public void setDepartureId(Long departureId) {
this.departureId = departureId;
}
public Long getReturnId() {
return returnId;
}
public void setReturnId(Long returnId) {
this.returnId = returnId;
}
public Category getDepartureFlight() {
if (departureFlight == null) {
this.departureFlight = service.getFlightById(this.departureId);
}
return this.departureFlight;
}
public Category getReturnFlight() {
if (returnFlight == null) {
this.returnFlight = service.getFlightById(this.returnId);
}
return this.returnFlight;
}
public boolean hasReturnFlight() {
return this.returnId != null;
}
public String chooseFlight() {
return "details.jsf?faces-redirect=true";
}
public String proceedToPayment() {
System.out.print("Proceeding");
return "../pay.jsf";
}
}
Im getting my primefaces scaffold ready for my developers and I have a problem. When I do a form submit with validation via AJAX, it displays the message right, but the return deletes all but the first field in the form. Its almost like something screwy in the return ajax call is causing everything after the first text field to fail to render. If I do a standard form submit button, it works just fine, but just with the ajax submit (which of course is the one i want to use) it acts weird. Any ideas?
My index.xhtml page. Just look for header="New Person", pasted it right out of the showcase
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:core="http://highmark.com/dtmcore"
xmlns:inq="http://highmark.com/dtminq"
template="templates/default.xhtml">
<ui:define name="navDisplay">
<ui:include src="navBar/mainNavBar.xhtml" />
</ui:define>
<ui:define name="content">
<script type="text/javascript">
$(document).ready(
function() {
jvers = $.fn.jquery;
$("#testJQueryLoaded").text(
"jQuery Loaded Correctly version " + jvers);
});
</script>
<div class="row clearfix">
<div class="col-md-12 column">
<div class="row clearfix">
<div class="col-md-12">
<div class="jumbotron">
<h2>Inquiry App System</h2>
<p>This page right now is used primarily for testing controls
and layout</p>
<p></p>
<span id="testJQueryLoaded"></span> <br />
<h3>Your application can run on:</h3>
<h:graphicImage library="gfx" name="dualbrand_as7eap.png" />
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-12">
<div class="well">
<h:form id="form">
<p:panel id="panel" header="New Person" style="margin-bottom:10px;">
<p:messages id="messages" />
<h:panelGrid columns="3">
<h:outputLabel for="firstname" value="Firstname: *" />
<p:inputText id="firstname"
value="#{pprBean.firstname}" required="true" label="Firstname">
<f:validateLength minimum="2" />
</p:inputText>
<p:message for="firstname" />
<h:outputLabel for="surname" value="Surname: *" />
<p:inputText id="surname"
value="#{pprBean.surname}" required="true" label="Surname"/>
<p:message for="surname" />
</h:panelGrid>
</p:panel>
<p:commandButton value="Ajax Submit" update="panel,display" id="ajax"
actionListener="#{pprBean.savePerson}" styleClass="ui-priority-primary"/>
<p:commandButton value="Non-Ajax Submit" actionListener="#{pprBean.savePerson}"
ajax="false" />
<p:commandButton value="With Icon" actionListener="#{pprBean.savePerson}" id="withIcon"
update="panel,display" icon="ui-icon-disk" />
<p:commandButton actionListener="#{pprBean.savePerson}" update="panel,display" id="iconOnly"
icon="ui-icon-disk" title="Icon Only"/>
<p:commandButton value="Disabled" disabled="true" id="disabled" />
<p:panel id="display" header="Information" style="margin-top:10px;">
<h:panelGrid columns="2">
<h:outputText value="Firstname: " />
<h:outputText value="#{pprBean.firstname}" />
<h:outputText value="Surname: " />
<h:outputText value="#{pprBean.surname}" />
</h:panelGrid>
</p:panel>
</h:form>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-6">
<ui:include src="modules/buttonExample.xhtml" />
</div>
<div class="col-md-6">
<p:outputPanel id="displayHotkey">
<p:outputLabel value="Hotkey Result" />
<br />
<h:outputText value="#{hotkeyController.keyText}"
rendered="#{not empty hotkeyController.keyText}" />
</p:outputPanel>
</div>
</div>
<div class="row clearfix">
<div class="col-md-6">
<ui:include src="modules/datePickerExample.xhtml" />
</div>
<div class="col-md-6"></div>
</div>
<div class="row clearfix">
<div class="col-md-12">
<div class="well">
<h2>Members</h2>
<br />
<h:panelGroup rendered="#{empty members}">
<em>No registered members.</em>
</h:panelGroup>
<p:dataTable id="dataTable" var="_member" value="#{members}"
rendered="#{not empty members}"
styleClass="table table-striped table-bordered">
<p:column>
<f:facet name="header">Id</f:facet>
#{_member.id}
</p:column>
<p:column>
<f:facet name="header">Name</f:facet>
#{_member.name}
</p:column>
<p:column>
<f:facet name="header">Email</f:facet>
#{_member.email}
</p:column>
<p:column>
<f:facet name="header">Phone #</f:facet>
#{_member.phoneNumber}
</p:column>
<p:column>
<f:facet name="header">REST URL</f:facet>
/rest/members/#{_member.id}
</p:column>
<f:facet name="footer">
REST URL for all members: /rest/members
</f:facet>
</p:dataTable>
</div>
</div>
</div>
</div>
</div>
</ui:define>
<ui:define name="hotkeyMenu">
<ui:include src="hotkeyBar/hotkeyExample.xhtml" />
</ui:define>
</ui:composition>
And my template file (so far, work in progress)
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>#{app.applicationName}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>#{app.applicationName}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="" />
<meta name="author" content="" />
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
.sidebar-nav {
padding: 9px 0;
}
</style>
<h:outputStylesheet name="css/bootstrap.min.css" />
<h:outputStylesheet name="css/inquiry.css" />
<h:outputScript library="primefaces" name="jquery/jquery.js" />
<h:outputScript library="js" name="respond.min.js" />
<h:outputScript library="js" name="bootstrap.min.js" />
<!-- <h:outputScript library="js" name="bootstrap-dropdown.js"/> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</h:head>
<h:body>
<div class="container">
<div class="row">
<div class="col-md-12 column">
<ui:insert name="navDisplay">[Navigation Display inserted here]</ui:insert>
</div>
<div class="row show-grid">
<div class="col-md-11 column">
<div class="row">
<div class="col-md-12 column">
<ui:insert name="content">[Template content will be inserted here]</ui:insert>
</div>
</div>
</div>
<div class="col-md-1 column">
<ui:insert name="hotkeyMenu">[The Hotkey vertical bar goes here.]</ui:insert>
</div>
</div>
<div class="row">
<div class="col-md-12 column">
<p>United Concordia Rocks!</p>
</div>
</div>
</div>
</div>
<!--/.fluid-container-->
</h:body>
</html>
my backing bean
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.primefaces.context.RequestContext;
#ManagedBean(name = "pprBean")
#SessionScoped
public class PPRBean implements Serializable {
private String firstname;
private String surname;
private String city;
private String suburb;
private Map<String, String> cities = new HashMap<String, String>();
private Map<String, Map<String, String>> suburbsData = new HashMap<String, Map<String, String>>();
private Map<String, String> suburbs = new HashMap<String, String>();
private Map<String, String> rooms = new HashMap<String, String>();
private Map<String, Map<String, String>> itemsData = new HashMap<String, Map<String, String>>();
private Map<String, String> items = new HashMap<String, String>();
private String room;
private String item;
private String[] selectedCities;
public PPRBean() {
cities.put("Istanbul", "Istanbul");
cities.put("Ankara", "Ankara");
cities.put("Izmir", "Izmir");
Map<String, String> suburbsIstanbul = new HashMap<String, String>();
suburbsIstanbul.put("Kadikoy", "Kadikoy");
suburbsIstanbul.put("Levent", "Levent");
suburbsIstanbul.put("Cengelkoy", "Cengelkoy");
Map<String, String> suburbsAnkara = new HashMap<String, String>();
suburbsAnkara.put("Kecioren", "Kecioren");
suburbsAnkara.put("Cankaya", "Cankaya");
suburbsAnkara.put("Yenimahalle", "Yenimahalle");
Map<String, String> suburbsIzmir = new HashMap<String, String>();
suburbsIzmir.put("Cesme", "Cesme");
suburbsIzmir.put("Gumuldur", "Gumuldur");
suburbsIzmir.put("Foca", "Foca");
suburbsData.put("Istanbul", suburbsIstanbul);
suburbsData.put("Ankara", suburbsAnkara);
suburbsData.put("Izmir", suburbsIzmir);
rooms.put("Living Room", "Living Room");
rooms.put("Kitchen", "Kitchen");
rooms.put("Bedroom", "Bedroom");
Map<String, String> livingRoomItems = new HashMap<String, String>();
livingRoomItems.put("Sofa", "Sofa");
livingRoomItems.put("Armchair", "Armchair");
livingRoomItems.put("Coffee Table", "Coffee Table");
Map<String, String> kitchenItems = new HashMap<String, String>();
kitchenItems.put("Refrigirator", "Refrigirator");
kitchenItems.put("Dishwasher", "Dishwasher");
kitchenItems.put("Oven", "Oven");
Map<String, String> bedroomItems = new HashMap<String, String>();
bedroomItems.put("Bed", "Bed");
bedroomItems.put("Wardrobe", "Wardrobe");
bedroomItems.put("Drawer Chest", "Drawer Chest");
itemsData.put("Living Room", livingRoomItems);
itemsData.put("Kitchen", kitchenItems);
itemsData.put("Bedroom", bedroomItems);
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public void savePerson(ActionEvent actionEvent) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("You've registered"));
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getSuburb() {
return suburb;
}
public void setSuburb(String suburb) {
this.suburb = suburb;
}
public Map<String, String> getCities() {
return cities;
}
public void setCities(Map<String, String> cities) {
this.cities = cities;
}
public Map<String, Map<String, String>> getSuburbsData() {
return suburbsData;
}
public void setSuburbsData(Map<String, Map<String, String>> suburbsData) {
this.suburbsData = suburbsData;
}
public Map<String, String> getSuburbs() {
return suburbs;
}
public void setSuburbs(Map<String, String> suburbs) {
this.suburbs = suburbs;
}
public void handleCityChange() {
if (city != null && !city.equals(""))
suburbs = suburbsData.get(city);
else
suburbs = new HashMap<String, String>();
}
public void handleRoomChange(ActionEvent actionEvent) {
if (room != null && !room.equals(""))
items = itemsData.get(room);
else
items = new HashMap<String, String>();
}
private boolean checked;
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
public String[] getSelectedCities() {
return selectedCities;
}
public void setSelectedCities(String[] selectedCities) {
this.selectedCities = selectedCities;
}
public String getSelectedCitiesAsString() {
if (selectedCities == null)
return "";
StringBuffer buffer = new StringBuffer();
for (String city : selectedCities) {
buffer.append("(");
buffer.append(city);
buffer.append(")");
}
return buffer.toString();
}
public Map<String, String> getRooms() {
return rooms;
}
public void setRooms(Map<String, String> rooms) {
this.rooms = rooms;
}
public Map<String, Map<String, String>> getItemsData() {
return itemsData;
}
public void setItemsData(Map<String, Map<String, String>> itemsData) {
this.itemsData = itemsData;
}
public Map<String, String> getItems() {
return items;
}
public void setItems(Map<String, String> items) {
this.items = items;
}
public String getRoom() {
return room;
}
public void setRoom(String room) {
this.room = room;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public void displayLocation() {
FacesMessage msg = new FacesMessage("Selected", "City:" + city + ", Suburb: " + suburb);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void reset() {
RequestContext.getCurrentInstance().reset("form:panel");
}
public void resetFail() {
this.firstname = null;
this.surname = null;
FacesMessage msg = new FacesMessage("Model reset, but it won't work.");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}
This is the screen as when you first come to it
If you click the ajax button, this is what returns. The normal submit works just fine
And here's what the JSF is returning in the ajax call. You can see, all the fields are included in the response, but its only displaying the first one
<?xml version="1.0" encoding="utf-8"?><partial-response><changes><update id="form:panel"><![CDATA[<div id="form:panel" class="ui-panel ui-widget ui-widget-content ui-corner-all" style="margin-bottom:10px;" data-widget="widget_form_panel"><div id="form:panel_header" class="ui-panel-titlebar ui-widget-header ui-helper-clearfix ui-corner-all"><span class="ui-panel-title">New Person</span></div><div id="form:panel_content" class="ui-panel-content ui-widget-content"><div id="form:messages" class="ui-messages ui-widget" aria-live="polite"><div class="ui-messages-error ui-corner-all"><span class="ui-messages-error-icon"></span><ul><li><span class="ui-messages-error-summary">Firstname: Validation Error: Value is required.</span></li><li><span class="ui-messages-error-summary">Surname: Validation Error: Value is required.</span></li></ul></div></div><table><tbody>
<tr><td><label for="form:firstname">Firstname: *</label></td><td><input id="form:firstname" name="form:firstname" type="text" value="" class="ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all ui-state-error" /><script id="form:firstname_s" type="text/javascript">//<![CDATA[
PrimeFaces.cw('InputText','widget_form_firstname',{id:'form:firstname'});
//]]><![CDATA[]]]]><![CDATA[></script></td><td><div id="form:j_id679843775_7ac2197c" aria-live="polite" class="ui-message ui-message-error ui-widget ui-corner-all"><span class="ui-message-error-icon"></span><span class="ui-message-error-detail">Firstname: Validation Error: Value is required.</span></div></td></tr>
<tr><td><label for="form:surname">Surname: *</label></td><td><input id="form:surname" name="form:surname" type="text" value="" class="ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all ui-state-error" /><script id="form:surname_s" type="text/javascript">//<![CDATA[
PrimeFaces.cw('InputText','widget_form_surname',{id:'form:surname'});
//]]><![CDATA[]]]]><![CDATA[></script></td><td><div id="form:j_id679843775_7ac21953" aria-live="polite" class="ui-message ui-message-error ui-widget ui-corner-all"><span class="ui-message-error-icon"></span><span class="ui-message-error-detail">Surname: Validation Error: Value is required.</span></div></td></tr>
</tbody>
</table></div></div><script id="form:panel_s" type="text/javascript">//<![CDATA[
PrimeFaces.cw('Panel','widget_form_panel',{id:'form:panel'});
//]]><![CDATA[]]]]><![CDATA[></script>]]></update><update id="form:display"><![CDATA[<div id="form:display" class="ui-panel ui-widget ui-widget-content ui-corner-all" style="margin-top:10px;" data-widget="widget_form_display"><div id="form:display_header" class="ui-panel-titlebar ui-widget-header ui-helper-clearfix ui-corner-all"><span class="ui-panel-title">Information</span></div><div id="form:display_content" class="ui-panel-content ui-widget-content"><table><tbody>
<tr><td>Firstname: </td><td></td></tr>
<tr><td>Surname: </td><td></td></tr>
</tbody>
</table></div></div><script id="form:display_s" type="text/javascript">//<![CDATA[
PrimeFaces.cw('Panel','widget_form_display',{id:'form:display'});
//]]><![CDATA[]]]]><![CDATA[></script>]]></update><update id="javax.faces.ViewState"><![CDATA[zSrt/a8fGazYeKThaR1kLCIZ9H+Byig1+R3m5/RMMwuGDQUZXOPr/aj4D7YpgH6NUcb5jAudj1QUNy6WMLUaVXYQrGkvy6fxpzBhHuvzVejCEMDhFVUj8d7NHCI=]]></update><extension ln="primefaces" type="args">{"validationFailed":true}</extension></changes></partial-response>
EDIT
I found it. Turns out its a bug in PrimeFaces with Websphere.
http://forum.primefaces.org/viewtopic.php?f=3&t=34650
Try
<p:commandButton value="Ajax Submit" update="panel,display" id="ajax"
actionListener="#{pprBean.savePerson}" styleClass="ui-priority-primary"
process="panel,display,#this"/>
And tell me more details about Back Bean to replicate :)