Hi Brien,

 
> Each interest has a code that would get sent if it's selected. 
> Some of the interests are displayed in a different style (bold).  
> I'm fairly new to Tapestry and have been going through the docs
> and examples and can't quite figure out the best way to do this. 
 
Here is how a similar situation could be implemented:
 
I'll start for the beginning for clarity. You can make a data object containing the data of the form (you can use several different objects as well, but for the sake of the argument let's assume that one is used). In this case, the object would have 'firstName', ' lastName', 'eMail' properties implemented using get and set methods. It would also have an 'interests' property that returns a Map of Boolean objects, indicating whether a particular interest has been selected or not. Let's say that the data object itself would be accessible from the page using the 'dataObject' property.
 
At initialization the page should set the data object to a new instance with the default settings (or set it to null, and do a lazy initialization in getDataObject() if it is null). The page initialization is best performed by overriding the initialize() method.
 
Once this is done, bind the text field values to 'dataObject.firstName', 'dataObject.lastName', etc. If the interests are hard coded (one component for each), then you can bind their checkbox values to 'dataObject.interests.Books', 'dataObject.interests.Music', etc. If they are coming from an array or sth like that, you can iterate over them using an Iterator component, say 'iterInterests', and then bind the value of the Checkbox component that is within the iterator to 'dataObject.interests[components.iterInterests.value]'.
 
In this way, you gain two things:
- The form will be initialized with the values within the data object when it is displayed
- The data object will be automatically filled in with the values from the user when the form is submitted.
 
All that remains is taking action when the form is submitted and the values set. This is usually done in the form's listener, typically named formSubmit(). In there you can check if the delegate contains any errors, check whether there are any errors due to dependencies between two or more fields and report them to the delegate so that the fields will be annotated appropriately during render, etc. If there are no errors, you can store the data in the database (an O/R technology comes very handy here).
 
Notice that you can use this page both to create new 'users' and to edit existing ones. To edit existing ones, you can do the following in the page that invokes the editing (I will assume that the page described above is called 'UserEdit'):
 
UserEdit page = (UserEdit) cycle.getPage("UserEdit");
page.setValueObject(valueObj); // set the values for the selected user
cycle.setPage(page); // transfer rendering to the UserEdit page
 
This is typically done within a Direct listener.
 
> I was thinking of creating a list of Interest objects with
> {code, label, selected, bolded} properties but I'm not sure
> how to handle fireObservedChange(). 
 
I don't think you need fireObservedChange() unless the list of interests (not the values!) is user specific. If it is the same for all users, then the list can be loaded on page load, on first demand, or anything like that -- there is no need to save it in the session. (This is the list that you can use in the iterator shown above)
 
If it is different for each user, then you do need to save it, however. You can do that by storing it in an 'interestList' property, and make it 'page persistent', for example:
 
void setInterestList(List interests) {
    _interestList = interests;
    fireObservedChange("interestList", interests);
}
 
This will keep the value within this session.
 
You will need to initialize _interestList in initialize() to the default value and call setInterestList() in the invoking Direct listener above.
 
> On a side note, how DO you deal with list/map properties in a form? 
> I think OGNL allows the expression "interests[5]" or
> "interests[Books].selected" but how do you make sure that change
> is observed by the PageRecorder?
 
See above. You do not need to use property recording using fireObservedChange() when dealing with a form, since the values are set from the submitted form. This is done in the rewind phase before the form listener (formSubmit()) is called. Basically the sequence of events on such a page is:
 
validate
rewind (set the values from the submitted form)
invoke listeners
render
 
Btw, if you have a primary key or something like that that identifies the user, but should not be displayed on the form, you can store it into a hidden field -- easier and more efficient than using a persistent page property.
 
You can find full OGNL reference at: http://www.ognl.org
 
>     The field validation framework seems very limited. 
> It (or FieldLabel, at least) doesn't seem to apply to anything but
> TextFields (i.e. it doesn't work with DatePicker, CheckBox,
> PropertySelection, etc?). 
 
I presume you mean ValidField here.
 
Please submit a feature request to have DatePicker support validation (it is very recent addition).
 
And I am curious, what would the validation on CheckBox and PropertySelection look like? In general, how do you think it could be made less limited?
 
> There aren't many Validators to work with, even for very common
> uses (e.g. Email, RegularExpressions).
 
Please submit a feature request, or better yet, contribute the code. The framework is expanded precisely in this manner.
 
I will leave the DatePicker issues to the authors, but I think that if there are problems and you are certain in them, you should submit a bug.
 
Bugs and feature requests: http://sf.net/projects/tapestry
 
I hope this is helpful.
 
Best regards,
-mb
 

 Brien Voorhees <[EMAIL PROTECTED]> wrote:

I was hoping to get some advice on how to handle the following in Tapestry.  We have a user signup form in which the user is presented with a list of "interests" to select.  It might look something like this :
---------------------------------------------------------------
First Name :
Last Name :
E-Mail :
etc...
SELECT INTERESTS :
[ ] Books    [X] Music   [ ] Movies
[ ] Finance  [ ] Computers [X] Cooking
[X] Games
---------------------------------------------------------------
Each interest has a code that would get sent if it's selected.  Some of the interests are displayed in a different style (bold).   I'm fairly new to Tapestry and have been going through the docs and examples and can't quite figure out the best way to do this. 
 
I was thinking of creating a list of Interest objects with {code, label, selected, bolded} properties but I'm not sure how to handle fireObservedChange(). 
 
On a side note, how DO you deal with list/map properties in a form?  I think OGNL allows the expression "interests[5]" or "interests[Books].selected" but how do you make sure that change is observed by the PageRecorder?
 
Other issues I've encountered in my first project using Tapestry, just FYI :
 
    The field validation framework seems very limited.  It (or FieldLabel, at least) doesn't seem to apply to anything but TextFields (i.e. it doesn't work with DatePicker, CheckBox, PropertySelection, etc?).  There aren't many Validators to work with, even for very common uses (e.g. Email, RegularExpressions).
 
    The DatePicker has display problems when it attempts to display over a list box.  The listbox renders on top of the DatePicker.
 
    The DatePicker has no options for the begin date range and defaults to starting at 1990.  This makes it unusable for birth dates. 
 
    Is there documentation available for the Table component yet?
 
 
Any help greatly appreciated,
Brien Voorhees   
 
 
 
   



Do you Yahoo!?
HotJobs - Search new jobs daily now

Reply via email to