O'Reilly logo

Mobile JavaScript Application Development by Adrian Kosmaczewski

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 4. Sencha Touch

Of all the frameworks presented in this book, Sencha Touch is probably the most complex and daunting of all. It is an amazing piece of JavaScript code, providing application developers with a fertile playground ready to be explored.

This chapter will provide an introduction to Sencha Touch, and will later explore its characteristics by creating three small applications from scratch.

Note

At the time of this writing, the current stable version of Sencha Touch is version 2.0.1.

Introduction and History

Sencha Touch is a fully fledged UI framework, in the same tradition as Cocoa Touch, Swing, or .NET. It is completely written in JavaScript, and it is a direct spin-off of the famous Ext.js framework, initially created in 2006 by Jack Slocum as an extension (hence the name) of the YUI framework from Yahoo!.

Sencha Touch provides a set of very complex widgets, reacting to the most complex gestures, geared towards the creation of extremely complex web applications. In this sense, Sencha Touch (and Ext.js) can be compared to Cappuccino, SproutCore, or other large-scale, enterprise-y frameworks.

Characteristics

And enterprise-y it is. Or at least that is how Sencha (the company behind Sencha Touch) is aggressively marketing it. Frameworks falling into this category usually have the following characteristics:

  • (Relatively) Large code footprint

  • Complex object hierarchy

  • Long list of widgets, with complex customizations, ready to be used out-of-the-box

  • Opinionated approaches to common tasks

  • Cross-browser support

  • Detailed documentation and a fanatical user base

  • Commercial support

Sencha Touch largely fills all of the requirements above, including the availability of an advanced designer tool: the Sencha Architect 2. This tool can be used to visually design user interfaces, using a tool similar to Interface Builder or Visual Studio, allowing developers to quickly create prototypes or complex user interfaces without having to write a single line of code. We are going to learn abut Sencha Architect at the end of this chapter.

Supported Platforms

Sencha Touch is a product of Sencha, which was formed after popular JavaScript library projects Ext.JS, jQTouch and Raphaël were combined. The first release of Sencha Touch was version 0.90 beta on July 17, 2010. This beta release supported iOS devices like iPhone, iPod touch, the iPad, and Android devices.

Subsequently, the first stable version 1.0 was released in November 2010. The latest stable version 2.0.1 adds support to BlackBerry devices running OS version 6. Version 2.0 has been released as Beta during SenchaCon 2011, held in Austin, Texas in October 2011, and in final version during the writing of this book, in March 2012.

Webkit Only!

It is very important to note that Sencha Touch is primarily based on Webkit, so it can support only webkit-based browsers like Chrome and Safari. This fact has a direct implication in the development process, because it means that you cannot use Firefox or Firebug to debug the application, and instead you have to use the equivalent tools provided by Safari or Chrome.

Key Features

Sencha Touch has several features that set it apart from other similar frameworks; in this section we are going to see some of them in detail.

GUI Controls

Sencha Touch includes a set of GUI-based controls or components for use within mobile web applications. These components are highly optimized for touch input.

Some GUI components available in the library:

  • Buttons with device specific themes and effects

  • Form elements like text fields (for email, date picker, address, etc.), sliders, selectors, and comboboxes

  • List component, which has momentum scrolling along with index

  • Minimalistic icon set

  • Toolbars/Menus

  • Movable tabs

  • Bottom toolbars

  • Map component with support to multi-touch input like pinch and zoom

  • All the components can be themed according to the target device (this is done using SASS, a stylesheet language built over CSS)

To demonstrate the large choice of GUI components available in Sencha Touch, the development team has built the Kitchen Sink, a rather extensive demo showcasing almost every possible control available in the library; you can take a look at the Figure 4-1.

Kitchen sink

Figure 4-1. Kitchen sink

CSS Transitions and Animations

Sencha Touch has certain built-in transition effects, based on the powerful CSS3 support that newer Webkit browsers have:

  • Slide over or under current element

  • Pop

  • Flips

  • Cube

Touch Event Management

Sencha Touch supports common touch gestures basically built from Touch events that are web standard but are supported only by iOS, Android OS, and some touch-enabled devices:

  • Tap

  • Double Tap

  • Swipe

  • Scroll

  • Pinch

However, care must be taken when handling many events in the same panel; for example, when handling single and double taps, the single tap event should trigger the creation of a delayed task, that should be removed if the user taps twice. It is somewhat unfortunate that the framework does not handle this situation by itself.

Application Data Support

Sencha Touch consists of both UI libraries and also data libraries. With the use of data libraries the mobile web application can get data from any remote server. Sencha Touch has a data package to support web standards for data interchange with server like AJAX and JSONP. It also supports YQL. Using these technologies, data can be bound to visual components like lists to reflect data from server.

One of the most interesting aspects of Sencha Touch regarding data management is the fact that lists (and other DataView panels) can be bound to data stores in such a way that they will be notified automatically of any change in the data store. Developers do not have to manually reload the list to reflect the changes in the data!

JavaScript Idioms

Sencha Touch has inherited from Ext.js a standardized (and opinionated) way of writing JavaScript; this has the advantage of simplifying the reading of code using these frameworks, but it also sometimes represents a slightly steep curve for developers new to the platform.

We are then going to spend a bit of time learning the classic Ext.js JavaScript idiom, which will make things easier to understand later on. Developers who have prior experience with Ext.js can jump or skim this section altogether, and start writing their first Sencha Touch application right away.

The idioms used by Sencha Touch are two:

  • Dictionaries for widgets

  • Method-based definition of classes and creation of instances

This section will describe these two patterns in detail.

Descriptive Dictionary Pattern

The first, most common idiom used by Sencha Touch is what I call the Descriptive Dictionary Pattern. Whenever you create a new instance of any Sencha Touch class, you are going to pass a dictionary of options to the function. For example, when you create your application, you write code like the following:

Ext.application({});

The Ext.application function takes a single parameter, a dictionary with options that are used to modify the behavior and look and feel of the application. Among those parameters, there are two very important ones that we are going to add:

name

A simple string without spaces used to generate a master namespace where all the objects of our application will be stored. This is similar to creating a global application JavaScript object, but instead Sencha Touch takes care of its creation automatically for us.

launch

This parameter takes a function and for all practical purposes, it is the entry point of the execution of our application.

Having said that, let me introduce to you a reasonable “Hello world” application in Sencha Touch 2:

Ext.application({
    name: 'SampleApp',
    launch: function() {
        Ext.Msg.alert('Hello, World!');
    }
});

Our objective is of course to create complex user interfaces; for that, we are going to use the singleton Ext.Viewport object, which serves a similar purpose as the default UIWindow instance used in iOS applications. The basic canvas where any other widgets can be drawn.

Just call the add() function of the singleton Ext.Viewport object to add any required subviews:

Ext.application({
    name: 'SampleApp',
    launch: function() {
        Ext.Viewport.add({});
    }
});

Just like when calling the Ext.application() method, the Ext.Viewport.add() function also takes a literal object as parameter; you just specify a dictionary with the proper types, and let Sencha Touch do the rest:

Ext.application({
    name: 'SampleApp',
    launch: function() {
        Ext.Viewport.add({    1
            xtype: 'tabpanel'
        });
    }
});
1

The object defined in this dictionary has the xtype property, which is very common in Sencha Touch.

We are going to learn more about the xtype property later in this chapter; for the moment, suffice to say that this parameter is used to determine the class of the object that will be created by Sencha Touch inside our Viewport object.

Object Orientation in Sencha Touch

Sencha Touch provides an abstraction around JavaScript’s own object orientation system, allowing developers to manage, in a small set of functions, the definition of classes and the creation of instances from those classes. In short, you use the Ext.define() function to… well, define a new class, and you use the Ext.create() function to create a new instance from any class.

For example, let’s see how to define a new Sencha Touch class:

Ext.define('ToDoListApp.model.Task', {
    extend: 'Ext.data.Model',

    config: {
        fields: [{
            name: 'id',
            type: 'int'
        },

        {
            name: 'completed',
            type: 'boolean'
        },

        {
            name: 'dueDate',
            type: 'date'
        },

        {
            name: 'title',
            type: 'string'
        },

        {
            name: 'description',
            type: 'string'
        }
        ],
        idProperty: 'id'
    }

    constructor: function(title) {
        if (title) {
            this.title = title;
        }

        return this;
    },

    markAsCompleted: function() {
        console.log(this.title + " is done!");
        this.completed = true;
    }
});

Now let’s see how we create a new instance from the class we have previously defined:

var task = Ext.create('ToDoListApp.model.Task', { title: 'Buy milk' });
task.markAsCompleted(); // logs "Buy milk: is done!" in the console

In the preceding code, we are not using the new keyword provided by JavaScript: new ToDoListApp.model.Task(). Instead, it is recommended to use Ext.create, since it allows you to take advantage of dynamic loading, which is a core feature of Sencha Touch.

Learn About the Sencha Touch Class System

It is strongly recommended to read the Class System Guide to learn more about the idioms used by Ext.js and Sencha Touch for defining and using classes.

Creating a To Do List App

The first application we are going to create with Sencha Touch is a very simple To Do List that allows users to:

  • Browse a list of tasks

  • Mark a task as completed (or not) by double tapping the task

  • Tasks are grouped by due date, so that it is easier to see what has to be done in each day

  • Add, edit, and remove tasks from the list

Finally, we are going to build this application as a single JavaScript file to begin with. We are going to break it into a proper MVC application after we have a working app. (See Figure 4-2.)

Sencha Touch To Do List

Figure 4-2. Sencha Touch To Do List

Create the HTML

The first thing to do is to create the HTML file that will hold the different pieces of the application. In our case, it will look like this:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Hello World</title>

    <script src="sencha/sencha-touch.js"></script>
    <link href="sencha/resources/css/sencha-touch.css" rel="stylesheet" />

    <script src="app.js"></script>
  </head>
  <body></body>
</html>

At this point you might ask yourself, but wasn’t Sencha supposed to be a JavaScript-only framework? Well, yes, but we need at least one HTML file for the browser to load all the different pieces of our application.

The HTML code itself is extremely simple; it just loads the two main files of the Sencha Touch framework: the JavaScript and the CSS stylesheet. The <body> tag, in particular, is completely empty, as Sencha Touch takes care of the complete initialization of any application built with it.

The biggest downside of Sencha Touch can be easily seen right now: the huge size of the library means that, in slow hardware, loading a Sencha Touch application can take up to a couple of seconds, which might or might not be acceptable for your users. Of course, as per Moore’s law, as mobile devices grow more powerful, this is becoming less and less of a problem (however, as this happens, these libraries keep growing, so it is a continuous fight between ease of development and performance, as a matter of fact).

Starting the Application Code

The code of the application is located in the app.js file. Remember that Sencha Touch is a pure JavaScript framework, and as such you create, manipulate, and destroy HTML elements through JavaScript, without ever writing a single line of HTML.

The first thing we are going to do is to create the basic skeleton of our application. This skeleton is constituted by the following elements:

  • An instance of Ext.Application, which is the base class for Sencha Touch applications. When a Sencha Touch application starts, the entry point is always the launch() method of this instance.

  • A master viewport panel, created by the application instance, which plays the same role as the UIWindow in an iPhone app, or the default activity in an Android application.

  • Inside the viewport, we are going to embed all the other screens, each stored in a separate variable (later, we will see how to embed these elements in separate files to create a more manageable application structure).

Let’s see the code that represents what we have just described:

Ext.Loader.setConfig({
    enabled: true
});

Ext.application({
    models: [
        'Task'
    ],

    controllers: [
        'TaskController'
    ],

    stores: [
        'TaskStore'
    ],

    views: [
        'TaskList',
        'TaskForm'
    ],

    name: 'ToDoListApp',

    launch: function() {
        Ext.Viewport.add([
                         Ext.create('ToDoListApp.view.TaskList'),
                         Ext.create('ToDoListApp.view.TaskForm')
        ]);
    }
});

If you remember our discussion about JavaScript at the beginning of this book, you will remember that it is important to scope the variables of a JavaScript application, so that the global namespace is not cluttered. This is what we are doing here: the ToDoListApp name is automatically converted by Sencha Touch in a variable, which works both as a pointer to the application instance and as a namespace in itself, where all the different widgets of the application will reside.

We can also see that the launch() method calls the Ext.Viewport.add() method of the Viewport singleton, which holds two instances of custom panels. You can think of a Container as an UIView in iOS or a View in Android; Containers are the basic building visual block of Sencha Touch applications.

And, similarly to other UI frameworks, you can embed Containers into Containers; the particularity in Sencha Touch is the use of the items property, which takes an array of Containers. This property simply adds the containers as children of the current one, and if you pass more than one container, the first is shown while the others are hidden.

Another important element of the definition above is the fact that Sencha Touch Viewports automatically use the layout: "card" instruction. This tells the container to use an instance of Ext.layout.CardLayout to display its children items, and it makes the parent only display a child container at a time. The CardLayout class also provides a setActiveItem() method that we are going to use in this application, in order to jump from container to container, using animations.

Transitions

One interesting property of the items property is that you can add several children panels to a parent panel, and then you can navigate from screen to screen, using similar animations as if you were using an UINavigationController in iOS. However, there is a greater flexibility to specify the types of animations, all powered using WebKit’s own CSS animations.

Creating Instances

Sencha Touch elements can be created both by using the Ext.create function, which requires the class name of the object, or by using dictionaries with the xtype keyword, which takes a special code as a parameter. When reading this parameter, Sencha Touch will automatically create the object of the corresponding class.

The following table shows the correspondence of the different classes available in Sencha Touch.

Table 4-1. Equivalence between instance creation syntaxes

CategoryxtypeClass

Basic

button

Ext.Button

component

Ext.Component

container

Ext.Container

dataview

Ext.DataView

panel

Ext.Panel

toolbar

Ext.Toolbar

spacer

Ext.Spacer

tabpanel

Ext.TabPanel

Form

form

Ext.form.FormPanel

checkbox

Ext.form.Checkbox

select

Ext.form.Select

field

Ext.form.Field

fieldset

Ext.form.FieldSet

hidden

Ext.form.Hidden

numberfield

Ext.form.NumberField

radio

Ext.form.Radio

slider

Ext.form.Slider

textarea

Ext.form.TextArea

textfield

Ext.form.TextField

Data

store

Ext.data.Store

arraystore

Ext.data.ArrayStore

jsonstore

Ext.data.JsonStore

xmlstore

Ext.data.XmlStore

To use the xtype syntax, just create a standard JavaScript dictionary and use it in the items or dockeditems property of your panel, just as if you would use any other instance:

Ext.define('ToDoListApp.view.TaskList', {
    extend: 'Ext.dataview.List',

    config: {

        items: [{
            xtype: 'toolbar',
            title: 'To Do List',
            items: [{
                xtype: 'spacer'
            },
            {
                xtype: 'button',
                iconCls: 'add',
                ui: 'plain'
            }]
        }]
    }
});

Stores, Proxies, Writers, and Readers

The diagram in Figure 4-3 shows the typical organization of a Sencha Touch 2 application. In this organization, the MVC standard is complemented by a series of supplementary objects, which serve as an abstraction layer for the underlying storage and communication mechanisms used by the application.

Sencha Touch 2 application architecture

Figure 4-3. Sencha Touch 2 application architecture

The first element in this mechanism is the Store. A Store represents an abstraction around data.

Views use stores directly (hence the direct connection between views and stores in Figure 4-3). One of the coolest features of this direct relationship is that views are 100% aware and dependent on the state of a store; this means that if you want to update a UI element attached to a store, you just update the store data, and the UI element will be updated automatically. This is a common mechanism in ASP.NET, for example, where it is known as data binding.

There are several different kinds of stores available:

  • Ext.data.Store is the base class used to represent stores; usually applications just create a raw instance of this class and use it as a store.

  • Ext.data.TreeStore is used to represent hierarchical data, and it is used with components such as the Ext.dataview.NestedList, used in the framework to represent nested sets of information.

Stores depend, in turn, of Proxies. These are instances of the Ext.data.proxy.Proxy class (or its subclasses), and they encapsulate the logic required for a particular storage technology. For example, there are proxies for the following types of storage:

Ext.data.proxy.Ajax

Allows the application to talk to a backend server, using the common CRUD methods. This is one of the most important proxies available; developers can customize them in many ways, like specifying the URLs for each of the API operations, and to pass parameters for each of those operations. A subclass of this proxy, Ext.data.proxy.Rest is specifically tailored for connecting to REST services.

Ext.data.proxy.JsonP

Another type of server-bound proxy, like the Ext.data.proxy.Ajax class; in this case, this proxy is able to read data from domains other than that of the original web application.

Ext.data.proxy.Memory

Stores data in an in-memory array, lost when the page is refreshed or when the user navigates away from the page.

Ext.data.proxy.LocalStorage and Ext.data.proxy.SessionStorage

Allow developers to store data in, you guessed it, the new HTML5 standard storage mechanisms.

Finally, server-bound proxies depend in turn on writers and readers. These classes, respectively located in the Ext.data.writer and Ext.data.reader namespaces, provide serialization and deserialization mechanisms for creating and reading XML, JSON payloads. Readers and writers are usually tied to server-bound proxies.

In our sample application, we are going to use a simple local storage proxy, which does not require a reader or a writer.

The Data Model

Sencha Touch uses the MVC architecture throughout its system. It allows developers to separate clearly the model classes from the view logic. It also allows developers to create adhoc stores, local or remote, to read and write those model instances.

In this sample, we are first going to write the application all in the same JavaScript file, and then we are going to separate the different elements in different files.

The first thing we are going to do in our app is to describe the model and the store where the model instances will be stored. This is the definition of a model class:

Ext.define('ToDoListApp.model.Task', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            {
            name: 'id',
            type: 'int'
        }, {
            name: 'completed',
            type: 'boolean'
        }, {
            name: 'dueDate',
            type: 'date'
        }, {
            name: 'title',
            type: 'string'
        }, {
            name: 'description',
            type: 'string'
        }],
        idProperty: 'id'
    }
});

As you can see, you can define all the characteristics of a Task, including the type and default values of each of its properties. In our case, a Task is defined by a numeric ID, a name, a description (both textual), a boolean value (stating whether the task has been done or not), and a due date.

Finally, we are specifying a proxy for our model, which provides the information of the location of the data. In this case we will be using the localStorage proxy, which means that the data will be stored as JSON objects in the HTML5 localStorage container of the browser.

Then we will specify a store for the model. A Sencha Touch store creates an intermediate object between your application controllers and the data they manage, allowing to provide information used to display the data in a meaningful way, such as its order or its grouping. In the case of our application, we are going to define the following Store:

Ext.define('ToDoListApp.store.TaskStore', {
    extend: 'Ext.data.Store',
    requires: [
        'ToDoListApp.model.Task'
    ],

    config: {
        model: 'ToDoListApp.model.Task',
        sorters: [{
            property: "dueDate",
            direction: "ASC"
        }],
        autoLoad: true,
        autoSync: true,
        singleton: true,
        storeId: 'TaskStore',
        proxy: {
            type: 'localstorage',
            id: "senchatasks"
        },
        grouper: function(record) {
            if (record && record.get("dueDate")) {
                return record.get("dueDate").toDateString();
            }
        }
    }
});

Creating the List

The first screen of our application is, of course, the list of tasks. In this screen we will display all the current tasks available, and whenever the application launches, it will synchronize the items available in the local database and display them:

Ext.define('ToDoListApp.view.TaskList', {
    extend: 'Ext.dataview.List',
    requires: [
        'ToDoListApp.store.TaskStore'
    ],

    config: {
        displayField: 'title',
        id: 'taskList',
        store: Ext.create('ToDoListApp.store.TaskStore'),
        itemTpl: '<div class="task completed_{completed}">{title}</div>',
        onItemDisclosure: true,
        emptyText: '<p align="center" class="instructions">No tasks here yet.<br/>Tap the "+" button to create one.</p>',
        grouped: true,

        items: [{
            xtype: 'toolbar',
            title: 'To Do List',
            docked: 'top',
            ui: 'light',
            items: [{
                xtype: 'spacer'
            }, {
                xtype: 'button',
                ui: 'plain',
                iconCls: 'add',
                iconMask: true,
                text: '',
                action: 'createTask'
            }]
        }]
    }
});

This is a very simple Ext.dataview.List that we are defining here; it will use the data store defined above as source of its data, and we are defining some useful properties, such as the fact that it will be grouped, and that every item shown will use a template.

Item templates are a very useful feature of Sencha Touch lists; they allow us to define the internal structure of each cell, and they are very similar to templates created using the jQuery Template plug-in.

One of the most interesting parts of the cell template is the fact that we can specify the data fields of each task, and how they are shown, just by encapsulating them between curly brackets.

Creating a To Do Item Form

The list is the first screen of our application. We also want to be able to create, edit, and delete To Do items, and for that we are going to create a form:

Ext.define('ToDoListApp.view.TaskForm', {
    extend: 'Ext.form.Panel',

    config: {
        id: 'taskForm',
        items: []
    }
});

The Ext.form.Panel class is there to help us. As usual, it takes a dictionary object with configuration options, and in particular, it uses a titlebar and two fieldsets; each one of these fieldsets will be rendered as its own group; the first fieldset contains all the data fields required to define a To Do item (see Figure 4-4):

{
    xtype: 'fieldset',
    id: 'mainFieldSet',
    instructions: 'Enter the details of the task',
    title: 'Task Details',
    items: [{
        xtype: 'textfield',
        id: 'titleField',
        label: 'Title',
        name: 'title',
        autoCapitalize: true,
        placeHolder: 'Enter a title'
    }, {
        xtype: 'textareafield',
        id: 'descriptionField',
        label: 'Description',
        name: 'description',
        autoCapitalize: true,
        placeHolder: 'Enter a description'
    }, {
        xtype: 'datepickerfield',
        id: 'dateField',
        label: 'Due on',
        name: 'dueDate',
        placeHolder: 'dd/mm/yyyy',
        dateFormat: 'D d M Y',
        picker: {
            slotOrder: [
                'day',
                'month',
                'year'
            ],
            yearFrom: (new Date()).getFullYear(),
            yearTo: (new Date()).getFullYear() + 10
        }
    }, {
        xtype: 'togglefield',
        id: 'completedField',
        label: 'Done',
        name: 'completed'
    }]
}
Form to create to do items

Figure 4-4. Form to create to do items

The second fieldset is shown only when the form is used to edit an item, and contains a single Delete button (shown in Figure 4-5):

{
    xtype: 'fieldset',
    id: 'taskFormDeleteFieldset',
    instructions: 'This cannot be undone',
    title: 'Actions',
    items: [
        {
        xtype: 'button',
        height: 44,
        id: 'deleteButton',
        ui: 'decline',
        text: 'Delete this task',
        action: 'deleteTask'
    }
Delete button

Figure 4-5. Delete button

The confirmAndDelete method asks the user for a confirmation before deleting the file, as shown in Figure 4-6.

A Controller to Rule Them All

The missing piece in our discussion of the MVC paradigm is, as you might have guessed, the controller. In Sencha Touch, controllers are defined as subclasses of the Ext.app.Controller class. They serve as the glue that ties models, stores and views together, and they provide a handy mechanism allowing developers to centralize all their application logic in a single place.

This is a very basic definition of a controller:

Ext.define('ToDoListApp.controller.TaskController', {
    extend: 'Ext.app.Controller',

    config: {
        id: 'taskController',
        refs: {
            saveButton: 'button[action=saveTask]',
            taskForm: '#taskForm',
        },
        control: {
            saveButton: {
                tap: 'saveTask'
            }
        }
    },

    launch: function () {
        this.updateTaskCount();
    },

    saveTask: function (button, e, eOpts) {
        // ... the code to save a task ...
        var form = this.getTaskForm();
        // ...
    }
});

A typical Sencha Touch controller is composed of three main sections:

  • A config object, itself containing two dictionaries:

    refs

    Contain references to individual UI widgets anywhere in the application

    control

    Defines, for each control, the event handlers that will be assigned.

  • A launch function, which is called after the main application launch function, and which serves as a good initialization point for the application

  • One or more event handling functions

Confirmation shown before removing an item

Figure 4-6. Confirmation shown before removing an item

Let’s analyze in detail how controllers work:

  1. The refs collection mentions the existence of a button, whose action parameter is the string saveTask. There is also a reference to the task edition form, whose ID is taskForm. Sencha Touch controllers can reference widgets and controls using either of these syntaxes, making it very easy for developers to pinpoint individual components all over the application.

  2. Later, in the control dictionary, we attach an event handler for the tap event on the button specified by the saveButton entry; the value of this event handler is a string, which is exactly the name of the method in the controller that will be fired when the user touches the button.

  3. Finally, the saveTask function contains the code that actually performs the requested action.

Another handy feature of the refs collection is that the controller will generate, automatically, getter methods that can be used to access individual components. For example, in the code above, the developer will be able to use the getTaskForm() method at any moment to retrieve a reference to that particular component.

Although nothing prevents developers from adding the event handling code directly in their views, controllers provide a handy and simple way to organize applications from the very beginning, allowing them to grow bigger and more complex as time passes.

Reacting to Events

There are many different event listeners that we can attach ourselves to, and the Sencha Touch documentation describes in great detail what is required for each one of them.

The most important listeners that you are going to use as a Sencha Touch developer are:

render

Called when the panel is drawn on screen for the first time. There are similar beforerender and afterrender listeners that are useful for the developer.

activate

Executed whenever the panel is active through the setActiveItem method.

itemtap

Executed whenever an item in the list is tapped.

orientationchange

As the name implies, this callback is executed after the device changes its orientation.

Each event requires a function with a particular signature; the Sencha Touch documentation describes in detail their structures.

Note

The saveTask event handler in our controller has exactly the same parameters specified in the Sencha Touch documentation; you can find all of these parameters in their corresponding documentation, and it is strongly suggested to specify them all, even if the dynamic nature of JavaScript makes this an optional feature.

Navigation

How does the application navigate from one screen to the other? As you can see by yourself, the application allows you to follow a navigation pattern very similar to that of the UINavigationController class in iOS, where one screen is pushed after the other, and a Back button allows you to return to where you were.

However, in Sencha Touch there is no such thing as a navigation controller, and thus you must handle the navigation manually. In the case of the To Do List application, there are basically two transitions:

  1. From the list to the form

  2. Back from the form to the list

The first animation is triggered every time you touch the + button, or every time you select an item in the list. In both cases, the magic is created by using the setActiveItem() method of the Panel class. This method accepts parameters that define the kind and direction of the transition to be used.

This method is called in the Viewport instance, which has two items: the list and the form. Our controller triggers the navigation, passing some parameters, as required by the user:

showForm: function() {
    Ext.Viewport.getLayout().setAnimation({
        type: 'slide',
        direction: 'left'
    });
    Ext.Viewport.setActiveItem(this.getTaskForm());
},

showList: function() {
    Ext.Viewport.getLayout().setAnimation({
        type: 'slide',
        direction: 'right'
    });
    Ext.Viewport.setActiveItem(this.getTaskList());
},

The viewport is just a panel, containing the list of to do items and a toolbar, and the second one is the task form. The setActiveItem() function is used to jump from panel to panel, creating the illusion of a transition between both.

The concept of the viewport is central to Sencha Touch, and this singleton object is a standard way to designate the root view that is visible at all times in the application. iOS developers can think of the viewport as the UIWindow instance where all the application is drawn and displayed.

Using Sencha Architect 2

As you have seen in this chapter, the creation of a Sencha Touch application uses a fairly descriptive, JSON-like structure of code. Developers use this to literally describe each and every detail of the user interface, and Sencha Touch allows them to organize this code in separate files for convenience.

The fact that most of the UI of a Sencha Touch application can be described with literal objects is one of the keys behind the success of the Sencha Architect 2[19], a commercial tool provided by the creators of Sencha Touch. Sencha Architect is very similar in nature to the visual builders found in products like Visual Basic or Xcode, allowing developers to create user interfaces with a mouse.

Sencha Architect 2 provides developers and designers for a common tool, integrated with a code generator, that can be used to create fully fledged applications in a very short amount of time. It uses the common canvas UI paradigm, with a widget palette on the left pane, a central editor canvas, and a project browser plus a properties pane on the left. The properties pane displays all the editable properties of the currently selected object on the canvas or on the project browser.

Figure 4-7 shows the tool running on OS X.

Sencha Architect 2

Figure 4-7. Sencha Architect 2

Sencha Architect 2 is a commercial application.

Sencha Architect 2[20] is available for Mac, Windows and Linux, with a commercial license; a preview version, valid for 90 days, can be downloaded for free. It can be used not only to create and edit Sencha Touch applications, but also Ext.js ones.

Conclusion

Sencha Touch is a very complex framework, and of course this chapter scratches only the surface of what can be done with it. Currently it is available in version 2.0, bringing several new features over 1.0, like a brazenly fast rendering engine (based in CSS, and thus, hardware-accelerated in iOS devices), and a new class system, which is 100% similar to the one available in ExtJS 4, much faster and easier to use.

However, Sencha Touch has the major drawback of not being available for non WebKit-based mobile browsers, which dramatically limits its cross-platform support. It compensates this fact by a tremendously polished UI, one that truly sets it apart from other mobile frameworks, and by a solid architecture, which makes it a serious alternative for enterprise software users.



[19] Previously known as Sencha Designer.

[20] Sencha Architect 2 was in beta at the time of this writing.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required