I love data Models in ExtJS. They are extremely simple to use, but are amazingly powerful for driving robust JavaScript applications. In fact, I’ve gotten to the point where I use them in just about everything I do, and they are fast becoming an indispensible part of my JavaScript development approach.

A big part of the appeal of ExtJS data Models is their flexibility. While some data “plugins” in other JS frameworks certainly allow you mimic some of the behaviors of a data model, ExtJS’ data Model wins hands down because of its extreme flexibility. With a ExtJS Model, you can quickly and easily create powerful definitions of data objects (fields, data types, associations, validations, etc.) in your application. These models can then in turn be used to craft a data Store, which can themselves be plugged into many of ExtJS’ data components (DataView, Grid, Chart). What you end up with is a super-powerful, deeply-data-driven application in a ridiculously small number of lines of code.

Of course, the perfect complement to the simplicity and grace of ExtJS’s data Model is to “feed” it using ColdFusion. Below, I’ll outline how to retrieve data from CF, as well an extremely easy way (there are obviously more!) to format data from a ColdFusion query directly into an ExtJS data Model.

Note: For these examples, I am using ColdFusion 9 and ExtJS 4.0.7

ExtJS Models

As mentioned above, the ExtJS data Model allows you to create pretty powerful–and flexible–definitions for data objects in your application. The beautiful part about this is that you can create a Model out of pretty much any data structure that is presented to your application. This allows you to spend your time making your JavaScript application work the way you want it to, without being enslaved to a particular requirement for data formatting (or type, for that matter). So whether you’re consuming XML, JSON, JSONP, etc., the ExtJS Model is flexible and configurable enough to normalize the incoming data structure into what you ultimately want (and need) your data objects to be for your application.

ColdFusion Query to JSON

How does this relate to ColdFusion? Well, let’s say that you have an existing, remotely-accessible component that returns a query result. In ColdFusion 8 and above, you can specify the “returnformat=json” argument in your method invocation, and ColdFusion wil serialize the query object into a JSON-formatted string, and return it to your JavaScript application.

remote any function getqueryarrays() {
    fauxquery = querynew('id,name,age');
    queryaddrow(fauxquery,4);
    querysetcell(fauxquery,"id","1",1);
    querysetcell(fauxquery,"name","Joel",1);
    querysetcell(fauxquery,"age","31",1);
    querysetcell(fauxquery,"id","2",2);
    querysetcell(fauxquery,"name","Jason",2);
    querysetcell(fauxquery,"age","31",2);
    querysetcell(fauxquery,"id","3",3);
    querysetcell(fauxquery,"name","Godzilla",3);
    querysetcell(fauxquery,"age","100000",3);
    querysetcell(fauxquery,"id","4",4);
    querysetcell(fauxquery,"name","Batman",4);
    querysetcell(fauxquery,"age","0",4);
    return fauxquery;
}

The one downside of this approach is that you don’t have a lot of control over how ColdFusion formats the JSON that it returns. It looks something like this:

As you can see, ColdFusion’s JSON-encoding has done a few things:

  • To represent the data, it has created two arrays: one for the column definitions, and one for the data. I would prefer an array of objects, but this is CF’s default behavior…
  • Perhaps worse, all of the “keys” have been uppercased, regardless of the original case of the columns

In other JS libraries, you might have to do some pre-processing of the JSON in order to get the data into something more like an array of structures, and/or even re-work the casing on the keys (or modify the requirements in your app to account for the casing). This all, of course, assumes that you have control over the source generating the JSON. Good luck if you don’t!

Making the Model

With ExtJS’s data Model, the JSON formatting–and even the ultimate structure of the source data–just doesn’t matter. The Model is flexible enough to adapt, and you can easily configure it to consume just about any incoming structure/format that you can think of.

Here’s what we can do for our example data:

Ext.define('Person', {
    extend: 'Ext.data.Model',
    fields: [
        {name:"ID", type:'int'},
        {name:"NAME", type:"string"},
        {name:"AGE", type:"number"}
    ],
    proxy: {
        type: 'ajax',
        url: 'remote.cfc?method=getqueryarrays&returnformat=json',
        reader: {
             type: 'array',
             root: 'DATA'
        }
    }
})

Seriously, it’s that simple. We just tell the Model that we’d like to define a data object with a certain number of fields, and it’s smart enough to automatically find and create an association with the incoming data. Here’s how we did it:

  • The “fields” config option allows us to tell ExtJS what we want our data object to look like. Notice that in this example, the “name” attribute is upper-case. This matches the upper-case keys being returned from CF.
  • The “proxy” config allows us to tell the Model how we’ll retrieve the data that will build the Model. In this case, we’re using the AjaxProxy.
  • In the proxy, we’ve also defined a “reader.” This is where the flexibility really comes into play. For the reader type, “array” has been specified. This tells ExtJS, at the very least, that our data is in an array format. Next, we’ve specified a “root” of “DATA.” This tell ExtJS that the “DATA” array will contain the values for the field definitions that we’ve already created.

And with that, our Model is complete. We can now hook this up to a data store, and we’ll be able to use the store on any number of data-driven ExtJS components.

A Bit of Tweaking

Even though that’s pretty simple, we’re still a bit tied to the formatting that ColdFusion has returned–after all, we used the uppercase column names in our field definitions. But what if we don’t want uppercase field definitions in our Model?

While we can certainly leave it as is, the ExtJS Model allows us to alternatively map field definitions using the “mapping” attribute. For the ArrayReader, the mapping can be the position in the data structure, rather than the explicit field name. So with just a slight modification, we can easily map our fields as before, but also create arbitrary field names in our Model field definitions:

Ext.define('Person', {   
     extend: 'Ext.data.Model',   
     fields: [       
        {name:"theid", type:'int',mapping:0},       
        {name:"myname", type:"string",mapping:1},       
        {name:"myage", type:"number",mapping:2}   
     ]
})

Wrapping Up

As we’ve, ExtJS’s data Model is an extremely powerful and versatile way of creating robust data objects for JavaScript applications. Not only do they serve as a great foundation for ExtJS’ data-driven components, but they (perhaps more importantly) are flexible enough to suit just about any requirement for incoming data. So instead of having to craft your application around the arbitrary data definitions which come from systems over which you may not have any control, you can easily leverage ExtJS data Models to take back the reins and define data objects based on the needs of your application alone. Pretty awesome 🙂