Sencha Touch Overview

In June of this year, ExtJS made the big announcement that they were changing their name to Sencha. Also, they recruited some Javascript rockstars and release a new UI framework called Sencha Touch.

Sencha Touch is a high-level Javascript UI framework designed to run on touch-based devices. Currently, it targets the iPhone, the iPad, and Android based phones. What is interesting is that because its targeted devices are running WebKit, the framework can use all the features that HTML5 and CSS3 have to offer. It features beautiful interactive UI elements which mirror native iPhone interfaces, but not in a pixel-by-pixel way - they put their own touches into it.

I jumped in and used it to build the iPhone version of a Todo-list app I had been building. Here are my impressions of the framework so far.

  1. There are a plethora of UI controls and they look great. Go see their kitchen sink demo for all of them. Some still need polishing in places. 
  2. The framework is more like ExtJS/YUI/Dojo than jQuery in that it's a high-level MVC/widget-based framework.
  3. Documentation is very lacking right now.
  4. Code is beta and very unstable.
  5. There are plenty of sample code and is open source, so you can get into it if you are good at reading code and willing to do some digging.
  6. Not super lightweight. Latest version 0.95 is 295kb. (jQuery is 24kb)
  7. GPLv3 license. Commercial licence is $99 per developer seat. No per domain or per app license required.
  8. Have a somewhat rigid MVC model which requires you to code your models on their terms: I don't particularly like this.
  9. Has an interesting prototype-inheritance-based approach to configuring and instantiating widgets.
  10. There is a template language called xtemplate.

Now for some code!


App Initialization

The html of Sencha Touch apps generally have an empty body tag - everything is create on the fly from Javascript. The app init happens in: Ext.setup. Here's an example:

Ext.setup({
    tabletStartupScreen: 'tablet_startup.png',
    phoneStartupScreen: 'phone_startup.png',
    icon: 'icon.png',
    glossOnIcon: true,
    onReady: function() {
        // write your setup code here
    }
});

As arguments to setup, you provide the various different launch icons for different devices, and an onReady function. The onReady function would usually instantiate UI widgets and run other setup code.

Make the Widgets

Within onReady, you would instantiate the top-level widget for the app. Here's an example:

var tabs = new Ext.TabPanel({
    fullscreen: true,
    type: 'dark',
    sortable: true,
    items: [{
        title: 'Tab 1',
        html: '1',
        cls: 'card1'
    }, {
        title: 'Tab 2',
        html: '2',
        cls: 'card2'
    }, {
        title: 'Tab 3',
        html: '3',
        cls: 'card3'
    }]
});

This creates a TabPanel, which has three items - each corresponding to a tab, with their respective title, html, and cls attributes. In this simple example, we just specify the contents of each tab via simple html. The key-value pairs that are passed to the TabPanel into the constructor will all be set onto the TabPanel itself. So, that means tabs will have the attributes: fullscreen, type, sortable, and items - although items will be transformed into an event-capable array: Ext.util.MixedCollection, and each item will be transformed into a Panel. The items attribute generally contain the children of a container in Sencha Touch.

Using xtype to Instantiate Children

As you can see from the above example, instantiating a widget usually involve passing a nested object into its constructor, and the constructor will actually convert some of these specifications into child widgets. You can use the xtype attribute to specify the type of the child widget. One example of this is in creating a FormPanel:

var form = new Ext.form.FormPanel({
    scroll: 'vertical',
    title: 'Enter URL',
    items: [
        {
            xtype: 'fieldset',
            defaults: {
                labelAlign: 'left'
            },
            items: [{
                xtype: 'textfield',
                name : 'url',
                label: 'URL'
            }],
            instructions: 'Enter a valid URL.'
        }
    ]})

The form is a big nested structure of fieldsets, labels, textfields, and what-have-you's. By using xtype to specify the types of subcontrols, you can instantiate all the children of a panel simply by writing a big nested tree of objects and arrays. In his example, the type 'fieldset' gets mapped to Ext.form.FieldSet, and 'textfield' is mapped to Ext.form.TextField. Alternatively, you could instantiate each child control manually, like this:

var form = new Ext.form.FormPanel({
    scroll: 'vertical',
    title: 'Enter URL',
    items: [
        new Ext.form.FieldSet({
            defaults: {
                labelAlign: 'left'
            },
            items: [new Ext.form.TextField({
                name : 'url',
                label: 'URL'
            })],
            instructions: 'Enter a valid URL.'
        }
    ]}))

The Data Model

For data-driven controls - such as Lists and Trees, Sencha Touch requires that you use their data model abstraction. This means you can either implement their protocol on your existing data, or just use some helpers to do the conversion. I chose the latter approach because I am lazy.

To create a data model for use, you first need to register a model, like this:

Ext.regModel('Task', {
    fields: ['name', 'description']
});

You could also give it type metadata such as:

Ext.regModel('Task', {
    fields: [        {name: 'name', type: 'string'},        {name: 'description', type: 'string'}    ]
})

To convert an array of objects(with the prescribed fields) into an Ext data store, you would do:

var dataStore = new Ext.data.Store({
    model: 'Task',
    data: tasks
})

This will wrap both the array tasks and the objects included in the array to give them the ability to notify change listeners and so forth.

To bind dataStore to a List control, you would do:

var listControl = new Ext.List({
    store: dataStore
})

or bind it after the fact with bindStore:

listControl.bindStore(dataStore)

To create a Task object, you need to ask the model manager:

var task = Ext.ModelMgr.create({
    name: 'clean up',
    desc: 'About time.'
}, 'Task')

Template Language

Sencha Touch includes a template language, which notably is used to render list items in the Ext.List control. A template may looks like this:

'<tpl for="."><div class="task"><strong><span style="float: right">\
{count}</span>{name}</strong></div></tpl>'

Curlies are used to inject variable substitution. The for="." tells the template engine to start at the top level of an item in the data store. So count would resolve to item.count, and name resolves to item.name. The language is pretty featureful, more information here.

Wrap Up

This concludes a brief overview of Sencha Touch. If you want to learn more, dig into the samples and source code and start hacking.

You Might Also Like

blog comments powered by Disqus