Dynamic Flex Scaffolding for Grails via REST Services : Part 2 – Scaffold Generation

This is the second post about some my ‘generate a dynamic Flex scaffold for Grails’ experiment. In this post, I will talk about the way in which the UI elements are created in Flex and demonstrate the advantages and differences of using this approach.

The Flex Scaffold Builder.

Here is a fairly complex Domain Class:

class News {
    String url
    String title
    String description
    Date lastUpdated
    Date dateCreated
    Boolean published
    String newsType
    String author
    Date articleDay
    int rating
    String color

    static constraints = {
        title( nullable: false, widget:"textarea", blank:true)
        description( widget:"richtexteditor", nullable:true )
        dateCreated( display: false )
        lastUpdated( display: false )
        newsType( inList: [ 'breaking', 'amazing', 'awesome' ], widget:"list")
        author( inList:['bob', 'steve', 'che guevera'])
        url( url:true, blank: true)
        rating(range:0..5, widget:"hslider")
        color( widget:"colorpicker", nullable:true)
    }
}

 

This is the resulting view from the Flex Scaffolder:

News Scaffold

You probably noticed that there are a few more options here than the default HTML components that ship with vanilla Grails. For example, there is a little button next to the Article Day button that will pop up a Calendar and allow you to select a date. There is a Rich text editor for the description field. A color chooser is used for Color and the Ratings component uses what is called the Slider.

The inList constraint, in combination with the widget constraint also allows us to provide different ways of choosing items in a list, what I’ve done here is add a List whenever a list widget is chosen with the inList constraint. I know this is not hard to do with Vanilla Grails, but I figured I might need it somewhere down the road.

Let’s dig into some code. I think here is where the advantage of using a Rich Internet Application framework like Grails really shines in comparison with any combination of HTML and JavaScript.

Look into the Editor.mxml file, each of these files simply contain a setter to get a model definition.

First, we take the xml properties and order them based on their order attribute:

   properties = new XMLListCollection( x..property );
   properties.sort = new Sort();
   properties.sort.fields = [new SortField('@order', true)];
   properties.refresh();

 

With this information, we are then able to just iterate through them and generate the right domain classes. I simply combine switch statements based on property type, whether the property is in a list, and whether the property has a widget defined.

The actionScript syntax for this is very straightforward:

switch( property.@type.toString() ){
    case "class java.util.Date":
        formComponent = new DateField();
        break;
    case "class java.lang.Boolean":
        formComponent = new CheckBox();
        break;
    default: ...

 

If we compare this to the RenderEditor code, we can see that this is a little cleaner and Groovier,

    else if(property.type == Calendar.class)
        out << renderDateEditor(domainClass,property)
    else if(property.type == URL.class)
        out << renderStringEditor(domainClass,property)

 

And then each editor returns a bunch of text

  if(!cp) {
            return "<input id="\&quot;${property.name}\&quot;" name="\&quot;${property.name}\&quot;" type="\&quot;text\&quot;" value="\&quot;\${fieldValue(bean:${domainInstance},field:'${property.name}')}\&quot;" />"
        }
        else {
            if("textarea" == cp.widget || (cp.maxSize &gt; 250 &amp;&amp; !cp.password &amp;&amp; !cp.inList)) {
                return "<textarea cols="40" rows="5" name="\&quot;${property.name}\&quot;">\${fieldValue(bean:${domainInstance}, field:'${property.name}')}</textarea>"
            }

 

Now, please understand that this is not a criticism of the way in which the grails code is written. I actually think that being able to scaffold on the client side of REST services is just a little more intuitive and simple, since you end up dealing with object, not lines of text.

We are then able to take these objects and put them into a tree and assign them a label. The syntax for this cannot be simpler, it is:

formItem.addChild( formComponent )
form.addChild( formItem )

 

Dealing with inList:

One of the cool things about the way Flex handles XML is our ability to generate XMLList objects from parent XML nodes, the code to build the combobox for choosing inList constraints is as follows:

   formComponent = new ComboBox();
   ( formComponent as ComboBox ).dataProvider = property..inListValue;
   ( formComponent as ComboBox ).labelField = "@value";

 

The line where we call property..inListValue , that’s e4x. It basically says : find me all the children with the name inListValue and put them into a list, then build a combobox out of it. Pretty cool, huh?

So that’s Flex generation in a nutshell. With this mechanism, you can also define your own components and add them into the widget area of your domain class. Need a FlagChooser, no problem, just build it with Flex.

Next Steps:

Based on the work I’m thinking of doing for this
Part 3 of this series will cover Validators.
Part 4 of this series will cover Associations.
Part 5 of this series will cover data transfer and posting to the server.

2 thoughts on “Dynamic Flex Scaffolding for Grails via REST Services : Part 2 – Scaffold Generation

  1. Chris Norton

    Great article. Looking forward to parts 3,4, and 5 (and the plugin!)

    I have been experimenting with flex-scaffold. They are pretty far along using BlazeDS on the backend:

    http://www.grails.org/plugin/flex-scaffold

    It would be great to see a common flex scaffolding plugin with an option for either REST or BlazeDS persistence.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s