Wednesday, May 16, 2007

Creating a CRUD interface using widgets in tapestry

One thing that has now become possible is to create, update and delete items in your app model, all while never leaving the same page. A create can invoke a css-styled div, made to look like a dialog, which asks for a few field values, saves it and invokes an ajax response to update the master page. Same for edit, and for delete. The old way would have been to take you to a new page to do the create, or to pop up a full window and do the job with the aid of a bit of javascript.

I've been experimenting with the dojo dialog provided in tapestry 4.1.2 to do just this. It works very well. Now I want to add a little bit more intelligence to the form (in the dialog - let's call it the crud form). So for instance, if you choose an item from a selection (lets call it billableItem), other fields can react. In tapestry, the simplest way to do this is with the EventListener annotation. Rather than dreaming up some custom javascript to do it, you can do a little ajax request/response to update your form for you. Very cool.

There are a few challenges though. Since the crud form is itself asynchronous, and is told to update some components of the master page, we have a few problems when we try to get the information in our crud form to our app, so that the secondary fields can react. Obviously the billableItem selection needs to get to our app so that we can react, and this is typically done by submitting the form in question, while turning validation off and making sure it is asynchronous.

<component id="addBillableItemEventForm" type="Form">
<binding name="delegate" value="bean:delegate"/>
<binding name="clientValidationEnabled" value="true"/>
<binding name="success"
value="listener:addBillableItemEvent"/>
<binding name="async" value="ognl:true"/>
<binding name="updateComponents"
value="{'weekScheduler_billable_row'}"/>
</component>

<component id="billableItem" type="PropertySelection">
<binding name="displayName" value="literal:Billable Item"/>
<binding name="model"
value="ognl:billableItemSelectionModel"/>
<binding name="value" value="ognl:billableItem"/>
<binding name="validators" value="validators:required"/>
</component>

--

@EventListener(elements = "billableItem", events = "onchange",
submitForm = "addBillableItemEventForm",
async=true, validateForm = false)

The problem is that when our EventListener is invoked, telling that crud form to submit itself so that we can react, it goes and updates the master page and validates on the server side (the crud form is configured to validate on the client side). So then we have validation errors on required fields and such, which is not what we want. So we can't really have our EventListener submit this form, because that form needs to be configured the way it is.

@EventListener(elements = "billableItem", events = "onchange")

So what can we do to add our intelligence, short of developing some custom javascript as per usual?

3 comments:

Anonymous said...

replica bags wholesale india zeal replica bags replica bags online shopping

theesea said...

b4a41u7u68 q6s71p8p36 x1c12f0i48 p1x54g1n29 j8l46x4q39 g9r40i3v21

YvonneVesta said...

You get the iconic six/nine/12 subdial layout that goes with the column-wheel link flyback chronograph powered by the Calibre 4404. The iconic little bubble window at three o'clock still tells you the link date, great for keeping track of how many link days it's been since the robots took over. Of course, the Offshore crown guards are there too.