archived posts

Archive for the ‘general’ Category

Introducing Compaction

In compaction, general on September 24, 2009 at 11:14 pm

I’ve been very quiet on the blogging front for the past few weeks. Although I would like to tell you that I have been relaxing on the beach somewhere, sipping cocktails and working a tan, it would be a lie. I have actually been spending my spare time creating a new open source project that I would like to introduce today.

The project I have been working on is called compaction, a small flex library designed to take some of the hard work out of creating CRUD based applications.

Some of the notable benefits of using the library include:

  • Automatically detect user changes.
  • Automatically undo user changes.
  • Validate at the form level.
  • Convention over configuration data binding.
  • Disable buttons when validation fails.
  • Disable buttons until changes have been made.

Although providing you with a lot of useful stuff, it has been designed to be as unobtrusive as possible. You can use compaction on a single form just like this:

<!-- The edit model does the heavy lifting  -->
<model:EditModel id="model" />
<mx:Form id="form" width="100%">
    <mx:FormItem label="Name">
        <mx:TextInput id="nameInput" />
    </mx:FormItem>
    <mx:FormItem direction="horizontal">
        <mx:Button id="saveButton" label="Save" />
        <mx:Button id="cancelButton" label="Cancel"/>
    </mx:FormItem>
</mx:Form>
<!-- The binder wires the form components into the model -->
<binder:FormBinder source="{model}" target="{form}" />

The edit model represents the state (editing, changed, valid, saving etc) of the editing process while the behaviour is encapsulated by a number of actions accessible from the model.

  • model.edit (edit an object)
  • model.cancel (undo user changes)
  • model.save (persist user changes)

These actions are automatically enabled/disabled based on the state of the model. They also display useful tool tips when they are disabled to reduce confusion.

The form binder uses a convention over configuration approach to wire the form components into the model. I wont go into the conventions in this post but bindings on input fields are two way with user changes commited on “change” by default.

That concludes my very quick introduction to compaction, one of my main goals at this stage is to create a small sample application. I’d rather not reinvent the wheel here so if you know of an existing project that might benefit please let me know!

Flex Validation – Future Directions

In flexsnippet, general on September 3, 2009 at 1:13 pm

I’m currently working on creating a small flex library with the goal of simplifying the task of implementing common user interface logic. One of the areas that is of particular interest to me is validation. Although the built in flex validators are useful they lack some important functionality needed to use them in any non trivial application.

In particular, the flex validators are quite narrowly focused on the validation of individual components like the text input or date chooser. While that’s great it limits our ability to easily validate an entire form or re-use our validators outside mxml.

In the Java world when you want to validate an object you implement a single method that executes the desired validation routines and collects the results.

public class PersonValidator implements Validator {
  public void validate(Object obj, Errors e) {
    ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
    Person p = (Person) obj;
    if (p.getAge()  110) {
      e.rejectValue("age", "too.darn.old");
    }
  }
}

I think this is a great approach for three reasons:

  1. You can use your validators everywhere, not just in the UI
  2. Your validation routines are all grouped together in a single spot
  3. You can easily unit test your validation

So naturally I’m interested in bringing something like this to the Flex world. Using a fluent builder pattern I think I am getting to a position where the validation process is becoming fairly straightforward e.g.

public class CustomerValidator implements Validator {

  public var blackList:ArrayCollection = new ArrayCollection(["a@a.com"]);

  public function validate(builder:ValidationBuilder, item:Object): void {
    var customer:Customer = Customer(item);
    builder.string(customer.name, "name").notEmpty().minLength(3);
    builder.number(customer.age, "age").between(0, 110);
    builder.string(customer.email, "email").validEmail().notIn(blackList);
  }
}

When writing a validator most of the heavy lifting is done by interacting with the builder:

public interface ValidationBuilder {
  function get routines(): ValidationRoutines;
  function get messages(): ValidationMessages;

  function addError(error:String, key:String=null);
  function hasErrors(): Boolean;

  function isNull(value:Object, key:String=null): ValidationBuilder;
  function isNotNull(value:Object, key:String=null): ValidationBuilder;

  function string(value:String, key:String=null) : StringValidationBuilder;
  function number(value:Number, key:String=null) : NumberValidationBuilder;
  function date(value:Date, key:String=null) : DateValidationBuilder;
}

You can easily use the the results of your validators in mxml using syntax similar to this…

<v:ValidationListener source="{validator}" target="{nameText}" key="name"/>
<v:ValidationListener source="{validator}" target="{ageText}" key="age"/>
<v:ValidationListener source="{validator}" target="{emailText}" key="email"/>

You’ll notice that several things are missing from this small overview including how you trigger validation and what happens with the results. The short story is that validation is just one component in the overall functionality required when editing objects.

I’m working on simple solutions to the overall problem but today I wanted to discuss how the validation side of things is shaping up.