| Hippo CMS Version: |
versions v6.03.xx and up |
| Experience level: |
Backend Template Developer |
| Developer goals: |
Introduction
First, a statement of the problem:
The screen needs to display 3 drop down lists with:
- DDL1 Car Makes
- DDL2 Car Types by the Car Make picked in DDL1
- DDL3 Car Models by the Car Make in DDL1 and of the Car Type in DDL2
As values are selected in DDL1, the screen should refresh and populate DDL2 with valid values and set DDL3 blank. As values are selected in DDL2, the screen should refresh and populate DDL3 with valid values.
Delivering the content for the dropdowns
So in this process, the first step is to have the data for populating and filters to receive the data that we need. From the example zip, add the carTest/ directory to your src/site directory. This will be published to your hippo-cms site directory when you build, not the perfect location, but acceptable for our test. A better place for the code is the extension folder see Extending Hippo CMS. But for simplicity's sake, let's put the code in the src/site folder for now. Now we need to get our cocoon shoes on for a minute. The carTest/ dir has a sitemap which will process cars, cars/Make, and cars/Make/Type. This example was largely poached from the Cocoon Forms examples, which I would recommend looking at for reference. The important point to note is the format that the data is returned in. I have used the nodetree style as doc'ed here. The Cocoon example needed to be modified to return Hippo Style list info. Now let's test that our DDL data code is working. Once building your CMS, try:
http://localhost:50000/carTest/cars http://localhost:50000/carTest/cars/Audi http://localhost:50000/carTest/cars/Audi/TT
These should all return reasonable looking data. If they don't, go back and get them right. Error messages at later stages in the game are few and far between, but likely the data is just in the wrong format if the list is coming ot blank.
Backend template modifications
Now let's set up our first DDL. In the carListExample/ dir, I have given all the related Hippo Files. Let's look at a simple DDL first. For its values to be initially populated, in your business logic file you apply a rule as below:
<rule for="/root/make"> <selectionsource type="nodetree" dynamic="true" src="cocoon://carTest/cars"/> </rule>
I would test all 3 of the searches to see that they populate the DDL correctly.
Now that we have our 3 lists with data being returned and have verified that they are correctly formatted for DDL display, we need to build the plumbing for the auto-refresh. A submit-on-change tag in the layout file will tell the html to submit the page on a value change:
<dropdown id="/root/make">
<submit-on-change/>
</dropdown>
Code to process needs to be added to the business logic file:
<rule for="/root/make"> <selectionsource type="nodetree" dynamic="true" src="cocoon://carTest/cars"/> <events> <on-value-changed> <javascript> var list = "cocoon://carTest/cars/"; // base uri of the list var rootKey=event.source.getValue(); // get this widget's value var typeWidget=lookupWidget(event.source,"/root/type"); //lookup subcategory's element if (rootKey != null) { // set the selection list of field typeWidget.setSelectionList("cocoon://cocoon-cform-xmleditor/datasource/nodetree?source=" + list + rootKey); } else { typeWidget.setSelectionList(new Packages.org.apache.cocoon.forms.datatype.EmptySelectionList("Select a make first")); } // Always set the subregion value to null. Note that it will also fire an event on the "type" // widget if it already had a value. typeWidget.value = null; </javascript> </on-value-changed> </events> </rule>
Not very scary code, but a few things to note:
- When setting the selection list from the flowscript code, the objects want CForms Style lists, not Hippo Style lists. cocoon://cocoon-cform-xmleditor/datasource/nodetree?source=<yourlist> will transform Hippo Style to CForms Style for you. This is the step that got me in trouble the first time. It all makes sense as long as you remember that Hippo lives on top of CForms, and so when you are under the covers a bit, sometimes you need to get more native.
- Check to see if the value is null, if so you can use the built in function new Packages.org.apache.cocoon.forms.datatype.EmptySelectionList("Select a make first") to build a nice Empty Selection list message.
- Set the new lists value to null, this will trigger the next event and cause DDL3 to be correctly populated.
The code for the 3rd list is largely a mirror, I will leave review of that as an exercise for the reader.
Other handy side notes:
- You can set the initial choose item from list message in your messages.xml as below:
<message key="cms.cforms-editor.general.choose-from-list">--Choose--</message>
- I have no initial values for the DDLs, they come up as text boxes until they have valid values. You could set there values initially with a selection source in the business logic that returns no rows (i.e. <selectionsource type="nodetree" dynamic="true" src="cocoon://carTest/cars/thisvaluenotvalid"/>) Just depends on your requirement.
Contributed by Adam Steidley from Bluenog