PrimeFaces' p:wizard validation not working - validation

I have a p:wizard with some tabs. In the first tab, the user selects a value (t:selectOneRadio - I'm using Tomahawk). That's a required value.
If the user doesn't select a value, it won't go to the next tab, but no validation error is displayed. Hm.
If the user has chosen a value, goes to the next tab, goes back to the first tab and chooses a different value, it will behave as if no value was chosen this time. (No validation error either, but the second tab can't be invoked).
And even worse: The user chooses a value in the first tab, goes to the second tab, tries invoke an action from there... a validation message appears; it acts as if no value was chosen in the first tab.
Is there any explanation for this?
UPDATE
The solution suggested in the PrimeFaces forum worked for me. (Adding process="#this" to the commandButton.)

Another thing you might want to consider..
If you are having trouble with required fields across tabs, you can manually perform your own validations between steps by implementing a flow event in your wizard component.
public String onFlowProcess(FlowEvent event) {
//First perform check to see if the user is attempting to remove the last visitor
if ("confirm".equals(event.getNewStep()) && (visitors == null || visitors.isEmpty())) {
log.debug("Validation failed for empty visitors");
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Visit must have at least one visitor.", null);
FacesContext.getCurrentInstance().addMessage(null, msg);
return event.getOldStep();
}
return event.getNewStep();
}
And the .xhtml file I declare the flowListener event. Try this and see if the validation messages go away.
<p:wizard showNavBar="true" widgetVar="scheduler" flowListener="#{scheduleVisit.onFlowProcess}" showStepStatus="true">

UPDATE
The solution suggested in the PrimeFaces forum worked for me. (Adding process="#this" to the commandButton.) No idea why, though!

This sounds like it could be one of a couple possible issues. You may be getting a validation error however you may not have declared your messages component correctly, or it is not getting updated. If this is the case their may be validation errors that you just don't see rendered on the page.
From the Primefaces Guide 2.2 for the Wizard component:
AJAX and Partial Validations -
Switching between steps is based on ajax, meaning each step is loaded dynamically with ajax.
Partial validation is also built-in, by this way when you click next, only the current step is validated,
if the current step is valid, next tab’s contents are loaded with ajax. Validations are not executed
when flow goes back.
The other problem may be that your property is not getting set properly in the managed bean and this is causing validation problems. This seems more likely.
I am having trouble thinking why one would need validation other than 'Required' for a selectOneRadio? You have a limited number of choices and one must be picked, therefore an incorrect value or invalid value should not be possible.

You just need to put the attribute required true on your radio button.
ex:
<p:selectOneRadio required="true" requiredMessage="you must put it">
<f:selectItem itemLabel="Días Laborales" itemValue="diasLab" />
<f:selectItem itemLabel="Días Ticados" itemValue="diasTic" />
</p:selectOneRadio>

PrimeFaces' p:wizard validation problem
Step :1 customerInformation.xhtml
<?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.org/ui">
<p:wizard flowListener="#{customerForm.onFlowProcess}">
<p:tab id="information" title="Information">
<p:panel header="Customer Information">
<h:outputLabel value="First Name" for="fName"/>
<h:inputText id="fname" value="#{customer.fname}"/>
<h:outputLabel value="Last Name" for="lName"/>
<h:inputText id="lname" value="#{customer.lname}"/>
</panel>
</p:tab>
<p:tab id="details" title="Details">
<p:panel header="Customer Details">
<h:outputLabel value="Address Line 1" for="addressOne"/>
<h:inputText id="addressOne" value="#{customer.addressOne}"/>
<h:outputLabel value="Address Line 2" for="addressTwo"/>
<h:inputText id="addressTwo" value="#{customer.addressTwo}"/>
</panel>
</p:tab>
</p:wizard>
</html>
Step:2 Create bean class CustomerForm.java
public class CustomerForm implements Serializable {
private static final long serialVersionUID = 1L;
private String fName;
private String lName;
private String addressOne;
private String addressTwo;
private static Logger logger = Logger.getLogger(CustomerForm.class.getName());
/**
* Call this method in p:wizard tag
*
*/
public String onFlowProcess(FlowEvent event) {
logger.info("Current wizard step:" + event.getOldStep());
logger.info("Next step:" + event.getNewStep());
return event.getNewStep();
}
/**
* #return the fName
*/
public String getfName() {
return fName;
}
/**
* #param fName the fName to set
*/
public void setfName(String fName) {
this.fName = fName;
}
/**
* #return the lName
*/
public String getlName() {
return lName;
}
/**
* #param lName the lName to set
*/
public void setlName(String lName) {
this.lName = lName;
}
/**
* #return the addressOne
*/
public String getAddressOne() {
return addressOne;
}
/**
* #param addressOne the addressOne to set
*/
public void setAddressOne(String addressOne) {
this.addressOne = addressOne;
}
/**
* #return the addressTwo
*/
public String getAddressTwo() {
return addressTwo;
}
/**
* #param addressTwo the addressTwo to set
*/
public void setAddressTwo(String addressTwo) {
this.addressTwo = addressTwo;
}
}
Note: don't put required="true" in xhtml file

Related

OmniFaces <o:validateMultiple> resetting two PrimeFaces <p:selectOneMenu> after validation failed

I have an OmniFaces <o:validateMultiple> set to two <p:selectOneMenu>. The one dropdown box is for the home, the other for the away team (of a sports game).
The validator checks, if the combination of the two teams already exists in the schedule, if so, the validator method return false. (see table above in the example: combination already exists... the single item in the list)
Now the problem:
The two select boxes are reset to their null values, but in the background, they seem to keep the value.
The UI tells the user "selection has been cleared", but this is not what I or the users expect.
Example
Before: validation:
After validation:
QUESTION:
How can I restore the select boxes' values after validation fail or rather how do I simply keep the values?
I guess resetting the inputs is just JSF specified behavior?? 🤷‍♂️
Is it a problem with PrimeFaces (I guess not)?
Can it be done? If so, how?
PS: I don't think posting the JSF code for the select boxes could help here, but if it could, please leave a comment
JSF should preserve the state of the component tree as defined by the life cycle of the framework.
However, depending on how your JSF page functions you may choose to for example only partially process a page whenever an event occurs. In this case only the processed components will retain their state.
Let's take your use case as an example and first define a view:
<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:p="http://primefaces.org/ui" xmlns:o="http://omnifaces.org/ui"
xmlns:of="http://omnifaces.org/functions">
<h:head>
<title>SelectOneMenu Validation</title>
</h:head>
<h:body>
<h:form>
<o:validateMultiple id="validateMatch" components="home away"
validator="#{selectBackingBean.onValidateMatch}"
message="The combination already exists or is invalid!" />
<p:dataList value="#{selectBackingBean.matches}" var="match">
<f:facet name="header">Home / Away</f:facet>
#{match.home} vs #{match.away}
</p:dataList>
<br/><br/>
<p:selectOneMenu id="home" label="Please select home..." value="#{selectBackingBean.selectedHome}">
<f:selectItems value="#{selectBackingBean.teams}" var="team"
itemValue="#{team}" itemLabel="#{team}" />
</p:selectOneMenu>
<p:selectOneMenu id="away" label="Please select away..." value="#{selectBackingBean.selectedAway}">
<f:selectItems value="#{selectBackingBean.teams}" var="team"
itemValue="#{team}" itemLabel="#{team}" />
</p:selectOneMenu>
<h:panelGroup>
<br/>
<h:message for="validateMatch" />
<h:outputText value="OK!" rendered="#{facesContext.postback and not facesContext.validationFailed}" />
</h:panelGroup>
<br/><br/>
<p:commandButton value="Save" action="#{selectBackingBean.onSave}" update="#form" />
</h:form>
</h:body>
</html>
Let's also define the backing bean holding the view state and the model:
#Data
#Named
#ViewScoped
public class SelectBackingBean implements Serializable {
private List<String> teams;
private List<Match> matches;
private String selectedHome;
private String selectedAway;
#Data
#AllArgsConstructor
public class Match {
private String home;
private String away;
}
#PostConstruct
private void init() {
teams = Arrays.asList("Malmö FF", "GAIS", "IFK Göteborg", "AIK");
matches = new ArrayList<>(Arrays.asList(new Match("Malmö FF", "AIK")));
}
public boolean onValidateMatch(FacesContext context, List<UIInput> components,
List<String> values) {
return values.get(0) != values.get(1) && !matches.contains(new Match(values.get(0), values.get(1)));
}
public void onSave() {
matches.add(new Match(selectedHome, selectedAway));
}
}
If we now run this we get the following results:
If we keep going and eventually run into a validation error we get the following:
Notice how it constantly retains the state of all components throghout. There are components in OmniFaces and JSF that allow you to control the state of selected parts of the component tree to get away from this behavior.
I'm guessing there is something going on in your code or that you are somehow resetting the backing bean values connected to the components.

JSF Displaying Text in modal if INSERT operation was successful

What is the correct way to return a value from a method in a managed bean indicating a successful SQL DML operation such as INSERT or UPDATE
Based on the tutorials and some blogs I read online, it says that a good practice in returning values from a method contained in a ManagedBean is a String value of a facelet or the .xhtml page
(in other words, a view) to redirect to a webpage.
Like this.
Original version:
#ManagedBean(name="myBean")
public class MyBean{
public String register(){
String SQL = "INSERT INTO myTable(col1,col2) VALUES(?,?);
PreparedStatement ps = connection.prepareStatement(SQL);
ps.setString(1,someStringVariable1);
ps.setString(2,someStringVariable2);
ps.executeUpdate();
return "index"; //pointing to index.xhtml
}
}
How about if i want to know if the executeUpdate() method was successful?
I thought I'd just change it to something like
Modified version:
public int register(){
int isSuccessful = 0;
try{
String SQL = "INSERT INTO myTable(col1,col2) VALUES(?,?);
PreparedStatement ps = connection.prepareStatement(SQL);
ps.setString(1,someStringVariable1);
ps.setString(2,someStringVariable2);
isSuccessful = ps.executeUpdate();
}
return isSuccessful;
}
However, on the modified version I returned an int which I don't see as correct as per how JSF should work with ManagedBean (Please correct me if i'm wrong)
I asked because say I have a Twitter Bootstrap modal which has the following.
<div class="modal-body">
<h:form>
//....some code here...
<h:commandButton value="Submit" action=#{myBean.register()}
<h:outputText value=" #{myBean.whatToPutHere_ToKnowIf_addData()wasSuccessful}" />
</h:form>
</div>
I need to be able to show within the modal div that register() execution was successful.
What is the simplest and correct way to accomplish that?
I read somewhere that AJAX will help but right now, I have very little knowledge of AJAX so maybe a simple solution to this is better.
I'd appreciate any help.
Thank you.
You can use a bean variable:
#ManagedBean(name="myBean")
public class MyBean {
private boolean isSuccessful = false;
public boolean isSuccessful() { return isSuccessful; }
public String register(){
isSuccessful = ...
}
}
and in your xhtml
....
<h:commandButton value="Submit" action="#{myBean.register()}" />
<f:ajax execute="#form" render="outtext" />
</h:commandButton>
<h:panelGroup id="outtext">
<h:outputText value="any Text" rendered="#{myBean.successful} />
</h:panelGroup>
</h:form>

p:calendar AJAX updates only the second time

I have a problem with PrimeFaces calendar and ajax update.
I have a calendar and when I change the date on the UI I want to refresh another component. The problem is that the first time I change the date, the other component stays the same, but when i change the date a second time, the other component is updated with the correct value that I am expecting.
Here is my form:
<h:form>
<p:calendar
value="#{foo.dtValidade}">
<p:ajax update="criteriosDataGridTeste" event="dateSelect"
listener="#{foo.updateTeste}" />
</p:calendar>
<h:panelGroup id="criteriosDataGridTeste">
<td><h:selectOneMenu value="#{foo.idtpresult}">
<f:selectItem itemLabel="ok" itemValue="ok" />
<f:selectItem itemLabel="not ok" itemValue="not ok" />
</h:selectOneMenu></td>
</h:panelGroup>
</h:form>
I am using primefaces 3.0.1
By debugging I found out that the listener is being called before the value dtValidade is set.
But i thought it should be the other way.
Why is this happening?
A simplified version of my bean:
#ManagedBean(name = "foo")
#ViewScoped
public class Foooo {
private Date dtValidade;
private String idtpresult;
public Foooo() {
dtValidade = new Date();
idtpresult = "not ok";
}
public Date getDtValidade() {
return dtValidade;
}
public void setDtValidade(Date dt) {
this.dtValidade = dt;
}
public String getIdtpresult() {
return idtpresult;
}
public void setIdtpresult(String idtpresult) {
this.idtpresult = idtpresult;
}
public void updateTeste() {
Date now = new Date();
if (dtValidade.before(now)) {
idtpresult = "ok";
} else {
idtpresult = "not ok";
}
}
}
Am I missing anything?
Thanks in advance!
try this one
add in xhtml code in the h:form where yours calendar is
<p:remoteCommand name="rc" update="criteriosDataGrid" >
and in your ajax
<p:ajax
event="dateSelect" listener="#{foo.updateCriteria}" oncomplete="rc"/>
i dont know excatly if you need the rest of attributes of p:ajax

Validation with JSF 2 only wanted on submit

I have an issue with validation, as I only want validation to take place when the submit button is clicked on the screen, not when another button is clicked.
In the displayed page option1.faces is the main file option1.xhtml, and several included files. Below are fragments of code from the main page and two of the included files:
Code in option1.xhtml:
<h:inputText size="4" maxlen="5" id="teff1" value="#{option1.teff1}">
<f:validateDoubleRange minimum="#{option1.teff1Min}" maximum="#{option1.teff1Max}"
disabled="#{simulator.validate}"/>
</h:inputText>
Code in abundances0.xhtml that is included in option1.xhtml:
<h:selectOneMenu id="abundanceSet0" value="#{abundance.abunSet0}" style="height:25px; width:180px;">
<f:selectItems value="#{abundance.abunSetMap}"/>
</h:selectOneMenu>
<p:spacer width="37" height="0"/>
<p:commandButton value="Select Set" actionListener="#{abundance.selectSet0}" update="abundances0"/>
Code in footerButtons.xhtml that is included in option1.xhtml:
<h:message for="teff1" style="color:red"/>
<h:commandButton value="Submit" disabled="#{!login.loggedIn}" action="#{simulator.submit}" onclick="resetForm()"
actionListener="#{simulator.validate}" class="button"/>
The fragments of code from the corresponding beans are here:
MyOption1Bean:
#ManagedBean(name="option1")
#SessionScoped
public class MyOption1Bean implements Serializable {
// Lots of other private variables and objects
private String teff1;
private String teff1Min;
private String teff1Max;
// Option 1 constructor to initialze limits
public MyOption1Bean() {
ResourceBundle bundle = ResourceBundle.getBundle("com.csharp.validation");
teff1Min = bundle.getString("teff1Min");
teff1Max = bundle.getString("teff1Max");
}
public String getTeff1() {
return teff1;
}
public void setTeff1(String teff1) {
this.teff1 = teff1;
}
// Lots of getters, setters, methods, etc.
}
MyAbundanceBean:
#ManagedBean(name="abundance")
#SessionScoped
public class MyAbundanceBean implements Serializable {
// Lots of other private variables and objects
public String getAbunSet0() {
return abunSet[0];
}
public void setAbunSet0(String abunSet) {
this.abunSet[0] = abunSet;
}
public Map<String,String> getAbunSetMap() {
return abunSetMap;
}
public void selectSet0(ActionEvent e) {
selectSet(0);
}
// Lots of getters, setters, methods, etc.
}
MySimulatorBean:
#ManagedBean(name="simulator")
#SessionScoped
public class MySimulatorBean implements Serializable {
// Lots of other private variables and objects
private boolean validate;
// When validate is true disabled is false so validation takes place.
public boolean isValidate() {
return !validate;
}
// When navigating away from the home page to one of the options, reset the error
// and validate flags.
public void resetError(ActionEvent event) {
error = false;
validate = false;
}
// On clicking "Submit" this enables the validate flag.
public void validate(ActionEvent event) {
validate = true;
}
// On clicking "Submit" this gets the user's input, and if succesful sends it to an output file then
// navigate to a "Success" page, otherwise return to the original page.
public String submit() {
// Code to check for errors and output data to a file.
}
// Lots of getters, setters, methods, etc.
}
In option1 (the xhtml and the bean files) the user enters a value for teff1, which must be between teff1Min and teff1Max, which are obtained from a properties file. This works correctly, and if a value for teff1 is not given or is out of range, on clicking the "Submit" button, as given in the footerButtons.xhtml, the submit fails and and the <h:message/> tag displays an error.
However, before clicking "Submit", if the input field for teff1 is empty or has a wrong value,
the <p:commandButton value="Select Set" .../> in the included abundances0.xhtml does not work. It is supposed to update a display with a chosen menu, which otherwise it does. I set the immediate
attribute of <p:commandButton value="Select Set" /> to true, but it still does not work. I only want the validation to take place when the "Submit" button is clicked, and nothing else.
I tried an alternative way: where the flag validate in the simulator bean is used to disable the validation until it is wanted. Namely, when the option1 page is visited it is false, to disabled is true, and no validation is done until the submit button is clicked, at which point it is set to true, so disabled is false. Unfortunately, this dose not work, as JSF thinks the page is valid and navigates away from it before validation is performed. This is in spite of the fact that validate() is executed before submit() in the simulator bean. This is confirmed by inserting a print statement in each of them.
Does anybody have any idea as to what is going on?, and is there an easy way of making sure that validation only takes place when the submit button is clicked? Otherwise the display is locked up, and I'm unable to make the other buttons work.
Many thanks for the clarification, and I did exactly what you suggested. I did the following:
First I put immdiate="true" in the command button that selects a menu in my abundances0.xhtml file:
<p:commandButton value="Select Set" actionListener="#{abundance.selectSet0}" update="abundances0" immediate="true"/>
then I changed the action in my abundance bean java file:
public void selectSet0(ActionEvent e) {
selectSet(0);
FacesContext.getCurrentInstance().renderResponse();
}
but it still does not work. If I click the button nothing happens unless a valid value is already in the input field for teff1 in the option1.xhtml file at the beginning. I need this button to work, together with other ones like it, regardless of what is in the input field, until the submit button is clicked. As far as I can see, I am doing everything correctly.
Icidentally, I'm using JSF 2.0 with PrimeFaces 3.4.2 and Eclipse Indigo.
The <p:commandButton> processes by default the entire form, as in process="#form".
You need to tell it to process only itself, as in process="#this".
<p:commandButton ... process="#this" />
This way all input components in the same form won't be processed (converted/validated/updated).
First of all, validation in JSF is performed in one of the Faces lifecycle, to be more specific, it's done at PROCESS_VALIDATIONS phase. The only way to skip validation is to instruct the Faces' lifecycle to skip that phase.
In JSF input & command components have an immediate attribute, which means that those with a true value for it will be processed during the APPLY_REQUEST_VALUES phase, instead of going through the whole Faces' lifecycle.
Behaviour is slightly different depending of the type of component:
input components with immediate="true" will be validated at APPLY_REQUEST_VALUES phase instead of the PROCESS_VALIDATION one.
command components with immediate="true" will be executed at APPLY_REQUEST_VALUES phase instead of the INVOKE_APPLICATION one.
So, to skip validation, a possible approach would be to have a <h:commandButton /> with immediate="true" and then, at the backing bean side invoke either FacesContext.getCurrentInstance().renderResponse() or FacesContext.getCurrentInstance().requestComplete() to tell Faces to skip the remaining lifecycle phases.
So, in your select0 method should be:
public void selectSet0(ActionEvent e) {
selectSet(0);
FacesContext.getCurrentInstance().renderResponse(); // skip the remaining phases and go straight to RENDER_RESPONSE
}
NOTE: Bear in mind that when submitting a form with an immediate command will trigger the validation in all of the immediate inputs of that form.

Component for "priority table" in JSF?

In a certain page of our JSF application, the user sees a table listing many objects, which we will call "jobs". Let's say each job has a priority, which is nothing but a number, and in this screen the user is able to edit the priorities of the jobs.
However, two jobs can't have the same priority number. For this reason, I'm finding it hard to build an appropriate UI to deal with setting the priorities.
We tried a simple editbox in the beginning, but it soon became clear that it sucked: if the user wanted to lower the priority of a job from 100 to 50, he would have to manually "make room for that job" by adding 1 to jobs 50 to 99.
Now I'm thinking about a table in which the user could drag & drop the rows to visually adjust priority, without ever having to fiddle with priority numbers (in fact never seeing them), but I can't find such component. Does anybody know of such component or have any better UI suggestion?
I don't think you will find a component that will change the priority numbering for you. Instead you should invoke a re-ordering routine that would update the priority numbers accordingly after changing the priority.
Regarding drag-and-drop, I'll suggest that you look at RichFaces or ICEFaces. RichFaces got some very neat functionality for implementing the sort of thing you are talking about. I'll recommend that you have a look at the RichFaces demo page and try out the drag-drop support components. The RichFaces component set also got an Ordering List (under Rich Selects), but it doesn't seem to allow for changing the ordering by entering a number, rather it is done using up and down buttons.
How about take your current idea and let the computer do the job of making room?
If the user enters 50, display a warning that that job exists, ask if they want the new job inserted before or after the current number 50 or if they want to cancel the operation entirely. If their choice is to insert the entry, you reorder the other items in code.
Check out the jQuery table drag'n'drop plugin. Then just tie the resulting javascript calls into your back-end using Ajax (eg. the a4j:jsFunction from Richfaces). Get the back-end Bean to handle the shuffling of the subsequent jobs.
This will definitely look and behave better than any out-of-the-box component that you'll currently find in a JSF library.
I thought I'd have a go and see if you could do this with the out-of-the box components and script.aculo.us. It is possible, though there would be a bit of work in getting it to look nice and provide a slick UI.
The demo view:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<jsp:directive.page language="java"
contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" />
<jsp:text>
<![CDATA[ <?xml version="1.0" encoding="ISO-8859-1" ?> ]]>
</jsp:text>
<jsp:text>
<![CDATA[ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ]]>
</jsp:text>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Sortable</title>
<script src="javascripts/prototype.js" type="text/javascript">/**/</script>
<script src="javascripts/scriptaculous.js" type="text/javascript">/**/</script>
</head>
<body>
<f:view>
<h:form>
<h:dataTable id="table1" binding="#{jobPageBean.table}"
value="#{jobBean.jobs}" var="row" border="1">
<h:column>
<f:facet name="header">
<h:outputText value="jobs" />
</f:facet>
<h:outputText value="#{row.text}" />
<h:inputHidden value="#{row.priority}">
<f:convertNumber integerOnly="true" />
</h:inputHidden>
</h:column>
</h:dataTable>
<h:commandButton id="ucb1" binding="#{jobPageBean.updateCommandButton}"
action="#{jobBean.updatePriorities}" value="Save New Priority Order"
disabled="true" />
</h:form>
<h:form>
<h:inputTextarea value="#{jobBean.newJob}" />
<h:commandButton action="#{jobBean.addNewJob}" value="Add Job" />
</h:form>
</f:view>
<script type="text/javascript"> /* <![CDATA[ */
Sortable.create('${jobPageBean.tableClientId}:tbody_element', {tag: 'tr', onChange: sortElements});
function sortElements() {
var table = document.getElementById('${jobPageBean.tableClientId}');
var inputs = table.getElementsByTagName('input');
for(var i=0; i<inputs.length; i++) {
inputs[i].value = i;
}
var updateCommandButton = document.getElementById('${jobPageBean.updateCommandButtonClientId}');
updateCommandButton.disabled = false;
}
/* ]]> */
</script>
</body>
</html>
</jsp:root>
Beans:
public class JobPageBean {
// Declaration:
// <managed-bean>
// <managed-bean-name>jobPageBean</managed-bean-name>
// <managed-bean-class>job.JobPageBean</managed-bean-class>
// <managed-bean-scope>request</managed-bean-scope>
// </managed-bean>
private UIComponent dataTable;
private UIComponent updateCommandButton;
public void setTable(UIComponent dataTable) {
this.dataTable = dataTable;
}
public UIComponent getTable() {
return dataTable;
}
public String getTableClientId() {
FacesContext context = FacesContext
.getCurrentInstance();
return dataTable.getClientId(context);
}
public void setUpdateCommandButton(
UIComponent updateCommandButton) {
this.updateCommandButton = updateCommandButton;
}
public UIComponent getUpdateCommandButton() {
return updateCommandButton;
}
public String getUpdateCommandButtonClientId() {
FacesContext context = FacesContext
.getCurrentInstance();
return updateCommandButton.getClientId(context);
}
}
public class JobBean {
// Declaration:
// <managed-bean>
// <managed-bean-name>jobBean</managed-bean-name>
// <managed-bean-class>job.JobBean</managed-bean-class>
// <managed-bean-scope>session</managed-bean-scope>
// </managed-bean>
private List<Job> jobs;
private DataModel model;
private String newJob;
public DataModel getJobs() {
if (jobs == null) {
jobs = new ArrayList<Job>();
model = new ListDataModel(jobs);
}
return model;
}
public String updatePriorities() {
if (jobs != null) {
Collections.sort(jobs);
}
return null;
}
public String getNewJob() {
return newJob;
}
public void setNewJob(String newJob) {
this.newJob = newJob;
}
public String addNewJob() {
if (newJob == null || newJob.trim().length() == 0) {
return null;
}
Job job = new Job();
job.setText(newJob);
job.setPriority(jobs.size());
jobs.add(job);
newJob = null;
return null;
}
}
public class Job implements Comparable<Job> {
private String text;
private int priority;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public int compareTo(Job other) {
if (other.priority == priority) {
return 0;
}
return other.priority < priority ? 1 : -1;
}
}
You can reorder the rows by dragging them, but you need to submit the form to save the changes - you won't get good AJAX support without a 3rd party framework that adds it (at least, not until JSF 2.0)
I used MyFaces 1.2.3, the dataTable of which renders its tbody element with an id attribute ending in :tbody_element - I don't know if all implementations do this
I haven't bothered with too much in the way of input validation, or looked at using the keyboard for accessibility support, or all those other things required for a professional UI...

Resources