Pages

Sunday, March 02, 2008

Netbeans Visual JSF: Woodstock DropDown component using Calendar and Date objects

In this example, I will create a Netbeans Visual JSF Web Application using Woodstock DropDown components which use calendar and date objects. There will be some basic AJAX and validation.

Using Netbeans 6.0.1, create a new web application and select visual jsf as a framework.



This should create a visual web application.

Open the source packages directory from the Project window and click on the SessionBean1.java file. This class represents items which should be stored in the session which we want available between page views. Add the following properties to the bottom of the file:

private GregorianCalendar startCalendar;
private GregorianCalendar endCalendar;
private Date startDate;
private Date endDate;

public GregorianCalendar getEndCalendar() {
return endCalendar;
}

public void setEndCalendar(GregorianCalendar endCalendar) {
this.endCalendar = endCalendar;
}

public Date getEndDate() {
return endDate;
}

public void setEndDate(Date endDate) {
this.endDate = endDate;
}

public GregorianCalendar getStartCalendar() {
return startCalendar;
}

public void setStartCalendar(GregorianCalendar startCalendar) {
this.startCalendar = startCalendar;
}

public Date getStartDate() {
return startDate;
}

public void setStartDate(Date startDate) {
this.startDate = startDate;
}
After adding these component, right click on the page and fix imports. These properties will persist our values when we submit our page.

Next go back to the page and add 4 DropDown List and 4 StaticText components to the page from the palette. Add a DateTimeConverter and a CalendarConverter to the page. Right click on the staticText components and bind to data. Select bind to object and select startCalendar, on the next staticText field select endCalendar. Repeat for the remaining two staticText using start and end dates. After completing this select each component, and in the properties select the appropriate converter to be applied.





At this point we need to add a little Java to the backing bean. Add the following code to the page:



public Option[] getCalendars() {
ArrayList<Option> l = new ArrayList<Option>();
ArrayList<GregorianCalendar> calendars = new ArrayList<GregorianCalendar>();
GregorianCalendar gc = (GregorianCalendar) GregorianCalendar.getInstance();
gc.setTime(new Date());
gc.setTimeZone(TimeZone.getTimeZone("EST5EDT"));
gc.set(GregorianCalendar.HOUR_OF_DAY, 0);
gc.set(GregorianCalendar.MINUTE, 0);
gc.set(GregorianCalendar.SECOND, 0);
gc.set(GregorianCalendar.MILLISECOND, 0);
for (int i = 0; i < 24; i++) {
for (int j = 0; j < 60; j += 15) {
GregorianCalendar clone = (GregorianCalendar) gc.clone();
clone.set(GregorianCalendar.HOUR_OF_DAY, i);
clone.set(GregorianCalendar.MINUTE, j);
calendars.add(clone);
}
}
gc.set(GregorianCalendar.HOUR_OF_DAY, 24);
calendars.add(gc);
Collections.sort(calendars);
for (GregorianCalendar c : calendars) {
Option option = new Option();
option.setLabel(String.format("%02d", c.get(GregorianCalendar.HOUR_OF_DAY)) + ":" + String.format("%02d", c.get(GregorianCalendar.MINUTE)));
option.setValue(c);
l.add(option);
}
return l.toArray(new Option[l.size()]);
}

public Option[] getDates() {
ArrayList<Option> l = new ArrayList<Option>();
GregorianCalendar gc = (GregorianCalendar) GregorianCalendar.getInstance();
gc.setTime(new Date());
gc.setTimeZone(TimeZone.getTimeZone("EST5EDT"));
gc.set(GregorianCalendar.HOUR_OF_DAY, 0);
gc.set(GregorianCalendar.MINUTE, 0);
gc.set(GregorianCalendar.SECOND, 0);
gc.set(GregorianCalendar.MILLISECOND, 0);
for (int i = 0; i < 24; i++) {
for (int j = 0; j < 60; j += 15) {
GregorianCalendar clone = (GregorianCalendar) gc.clone();
clone.set(GregorianCalendar.HOUR_OF_DAY, i);
clone.set(GregorianCalendar.MINUTE, j);
Option option = new Option();
option.setLabel(String.format("%02d", clone.get(GregorianCalendar.HOUR_OF_DAY)) + ":" + String.format("%02d", clone.get(GregorianCalendar.MINUTE)));
option.setValue(clone.getTime());
l.add(option);
}
}
gc.set(GregorianCalendar.HOUR_OF_DAY, 24);
l.add(new Option(gc.getTime(), String.format("%02d", gc.get(GregorianCalendar.HOUR_OF_DAY)) + ":" + String.format("%02d", gc.get(GregorianCalendar.MINUTE))));
return l.toArray(new Option[l.size()]);
}



Note: Fix the imports, make sure that you choose import com.sun.webui.jsf.model.Option as the item to be imported.

Save and clean and build the application. This will refresh the framework so we can bind the new methods to our dropDown Lists.

Go back to the Design view. Click on the first two dropdown lists and bind them to the Page1.calendar items. Click on the next two items and bind them to the dates.


Next go to the properties and set the converters on the dropdown lists as appropriate. CalendarConverter on the first two dropdown lists and DateTimeConverter to the remaining dropdowns.

Next set the selected value to the appropriate property on the SessionBean1 Data Bean. startCalendar for dropDown1 and endCalendar for the second dropdown. Repeat for the date dropdowns. Add an appropriate label for each dropdown. I named them the same as the SessionBean1 property to be bound to.

Add a button and call it submit. Your example should look like this.


Next deploy the application and confirm that it works.

Next we will add some AJAX to the dropdown items. On dropDown1 add the following to the onChange event listed under the properties:
$('form1:dropDown1').submit(), $('form1:staticText1').refresh();
Repeat on the other dropdown components, but change the tags to point to the appropriate dropDown and staticText items.

Next, click on the calendarConverter1 component and change its properties: to

dateStyle: full
timeStyle: full
timeZone:EST5EDT
type: both
Repeat the process for the dateTimeConverter1.

We will now add a validator to dropDown2 which should be the endCalendar bound component. On the properties select validate under Events. Use the default handler listed. It should be dropDown2_validate


Go to Java source and navigate to the dropDown2_validate() method. Add the following code:


public void dropDown2_validate(FacesContext context, UIComponent component, Object value) {
GregorianCalendar end = (GregorianCalendar) value;
// dropDown1 is an AJAX component so the value on the backend is updated.
GregorianCalendar start = (GregorianCalendar) dropDown1.getValue();
if (start != null) {
if (end.compareTo(start) < 0) {
throw new ValidatorException(new FacesMessage("End Time must be greater than start time."));
}
}
}
Note: You need to ensure that you have both the start and end dropDown components. If they have different names, you will need to adjust the logic above to the appropriate dropDown component ids.

Your page should look something like this when you are done.



Redeploy the application. Check to see if the staticText fields update when you change values on the dropDown lists.



The submission should fail if the endCalendar is before the startCalendar.

I hope you enjoyed this brief tutorial. The files for the application are located here: CalendarDateDropDownExample.zip

Postscript: I asked for some folks at Sun to take a look at the page. They gave me some cool and interesting criticism of the tutorial.

One item that was not clear was that there are Woodstock components for calendars and schedulers. This is really an example of using a dropDown component with java.util.Calendar and java.util.Date.

It was suggested that I should use one or the other, but not both. Since this example is done, I will not change it. I will keep this in mind for future tutorials. The criticism was that it essentially was a duplication of effort and does not clearly state the case. I agree.

Additional Notes:


The project was developed using Netbeans 6.0/6.0.1 and Visual JSF (Project Woodstock 4.1.1). The latest version of Netbeans (6.1) includes Project Woodstock 4.2.

Project Woodstock has undergone a tremendous amount of changes from 4.1.1. This includes removing Prototype (JavaScript framework) and using a custom version of Dojo toolkit. The AJAX in this application depends on Prototype. You will need to install prototype in the project by adding a jar to the libraries. Here is prototype-1.5.0.jar.

10 comments :