Ibuildings blog

afbeelding van mdkeijzer

Getting started with Sencha Touch 2

The web as a mobile platform

The web has been a great place on desktops and laptops for quite some time, but with a booming growth of mobile devices like tablets and smartphones, the internet has become increasingly more interesting on these devices as well. Building mobile apps for the web has some advantages when compared to native development, before we start with Sencha Touch 2 we will take a look at these advantages.

If we look at 3 popular platforms there are a few distinctions which we need to keep in mind if we want to develop native applications for them:

Platform Main programming language Distribution method
Apple iOS Objective-C Apple App Store
Android Java Google Play, Amazon, etc
Windows Phone C# / Visual Basic Microsoft Market

As you can see in the table above there are a lot of dependencies which require a lot of different knowledge which makes it expensive and bug-sensitive to create the same application for all the platforms. Web applications have multiple advantages to overcome these issues:

  • Available through the web, so no app store submissions and reviews are required. This also makes your app immediately available when you require it.
  • Platform independent, the app can be used on any platform you want to support. In the end it all boils down to supporting browsers.
  • You have complete freedom over the user interface. If you want to create an app-like experience you can mimic the UI elements you like best from the native world or you can create your own unique branding.
  • Webapps can still be wrapped as native apps to push to the different app stores, options for doing this include Sencha Cmd and Adobe’s Phonegap (or the open source base implementation called Apache Cordova).

To achieve the goals mentioned above here you can make use of many web application frameworks, in this post we will focus on one of these; Sencha Touch 2. It has some advantages that make it a very strong framework for many business cases:

  • Very strong at building applications instead of shiny websites
  • All business logic is implemented using pure Javascript
  • It is a touch-enabled framework, which makes it a premium choice for touch-enabled devices
  • It has an (S)MVC pattern to have a good separation of concerns
  • It is based on the well known ExtJS 4 framework
  • Excellent documentation

Getting started with the Sencha SDK Tools

This article is based on Sencha Touch 2.1.0 RC2 and Sencha Cmd v3 beta

Sencha offers a great command line tool to get you up to speed very quickly, once you have downloaded and installed Sencha Cmd and the Sencha Touch 2 framework you can go to the framework’s folder and run the following command:

sencha generate app MyAwesomeApp ~/MyAwesomeApp

This will generate a new application for you with the namespace MyAwesomeApp in your home-folder. To view the generated app, you can use any Webkit based browser to open the generated index.html in your ~/MyAwesomeApp folder.

If we open up a file browser to investigate what has been generated we see a whole lot of files and folders, let’s dissect these and see what they do:

  • [directory] app: This is where the code of your application lives, it contains the views, data packages, profiles and controllers. In the rest of the article we will have a more thorough drill down of these folders.
  • [directory] resources: Here we will see static resources like the styling, images, splashscreens and icons for our app.
  • [file] app.js: The app.js file is the main bootstrap for your application, it determines the app name, icons, required classes and initiates the launch.
  • [file] *.json: In the main folder there are 2 JSON files, these are used for building the app. Once your app is ready to go live you can review these files or extend them to get everything you require in the distributable package.
  • [file] index.html: The main index file, it shows the preloader and initiates the app.js
  • [directory] touch: This directory contains the Sencha Touch SDK, do not touch this directory, whenever you want to upgrade the SDK of your project this directory will be overwritten and changes will get lost. If you want to customize SDK components it’s better to add in your own library directory and extend the objects from the SDK.

Creating a user interface

To make your app functional you will need to interact with your user, Sencha Touch 2 comes packed with many user interface components. These include:

  • Containers
  • Panels
  • Tab Panels
  • Carousels
  • Lists
  • Forms
  • Toolbars

These components are all highly configurable which makes them very powerful to quickly create a functional UI.

To get started with an example we will create a file in the app/view/ directory of our application, and we will call it Pictures.js
This view will be a picture gallery shown as a gallery which people can interact with by swiping the images. We have placed several images in the resources/images/ directory which we are going to use as the content for our gallery.

The content of this file will be as following:

Ext.define('MyAwesomeApp.view.Pictures', {
   extend: 'Ext.carousel.Carousel',
   xtype: 'employeescarousel',
 
   config: {
       items: [
           { html: '<img src="resources/images/1.png" />' },
           { html: '<img src="resources/images/2.png" />' },
           { html: '<img src="resources/images/3.png" />' },
           { html: '<img src="resources/images/4.png" />' },
           { html: '<img src="resources/images/5.png" />' }
       ]
   }
});

If we break down this code we see just 1 method call; Ext.define. This method creates a new class in the Sencha class system. The first argument is the name we want to give to our class, this name starts with MyAwesomeApp.view so the autoloader will detect it as an application class which is stored in the view directory. The last part of the class name is the actual name of the class which maps to your .js file. The second argument is an object which defines our class.

Since we want to use the carousel component to swipe through our content we extend the Ext.carousel.Carousel class and give it an xtype. The xtype defines the unique name for the component, keep in mind though that one components can have multiple instances so it is not comparable to the id-attribute of an HTML element.

Finally we add the configuration for our own carousel by defining the items in this carousel as an array of objects. By default a new item will be defined as a Panel-component. For our panel components we define it’s content by feeding it plain HTML code.

Now that we have defined our view we need to make our app aware that this view will be needed for the application. To achieve this we open the app.js in our root folder there we will find a key named views which is an array of strings, at the moment it only contains the generated ‘Main’ we modify the specification by adding our ‘Pictures’ view in it like this:

views: [
       'Main',
       'Pictures'
 ],

The final step to make the defined and initiated view available to our user is attaching it to one of the available components. If you have already taken a look at the generated application you will see that it contains a tab panel, to make our picture gallery available to our users we are going to add a new tab on this bar which will show the picture gallery view. For this we open the app/view/Main.js file and edit the configuration of the tab panel with a new item:

Ext.define('MyAwesomeApp.view.Main', {
   extend: 'Ext.tab.Panel',
   xtype: 'main',
   requires: [
       'Ext.TitleBar',
       'Ext.Video'
   ],
   config: {
       tabBarPosition: 'bottom',
 
       items: [
           { title: 'Welcome'...},
           { title: 'Get Started'...},
           {
               title: 'Employees',
               xtype: 'employeescarousel',
               iconCls: 'photos1'
           }
       ]
   }
});

Do not just copy and paste this example, for clarity's sake we have shortened the first 2 items of the configuration. Here we configure the title for the new tab, we tell it that the tab contains our newly created xtype employeescarousel and we attach a class for our icon to the tab (creating these icon classes will be explained later on).

Once we open up our app now we will have a new tab with the view we just created.

Congratulations, you have just created your first mobile web app! But of course we can do a lot more, let’s dive into the deep.

Taking control

As developers we like to have control over what is happening. Sencha Touch 2 offers various places to do this, but to keep your code clean, the best options are the bootstrap and the controllers.

Bootstrapping is a way to run code while the application is still booting and not yet used by our user. The bootstrap in Sencha Touch 2 is defined as a method called launch in your controllers. The generated app already contains a bootstrap in the app.js in the root folder. It is good to keep in mind that classes defined as controllers and profiles can also contain a launch method which are being run as bootstrap, the bootstrap in these files get executed before the one defined in your main app file.

Let’s see what will happen if we ad a simple alert box to our application once it gets booted by modifying the launch method of the app.js in our root folder:

launch: function() {
       // Destroy the #appLoadingIndicator element
       Ext.fly('appLoadingIndicator').destroy();
 
       // Initialize the main view
       Ext.Viewport.add(Ext.create('MyAwesomeApp.view.Main'));
 
       // Taking control in our bootstrap
       Ext.Msg.alert('Welcome', 'Welcome to my first awesome app!');
   },

In our example we have added the Ext.Msg.Alert which takes a title and a message as it’s arguments. When we reload our app in the browser we get an alert message component which shows this text. So as we can see, we can already take control before the user has done any interaction with our application.

Most of the times we will also want to take control of the events like user interactions with the app (e.g. tapping a component). In our example we are going to change the code for our html panels in /app/view/Pictures.js into a more specific type of component so we can interact with it in an easy way in the next steps:

{
        xtype: 'img',
        src: 'resources/images/1.png'
    },

The next step is to open a terminal and go to the directory where we generated our app, in our example this is ~/MyAwesomeApp and we run the following command:

sencha generate controller PictureTab

This creates a new controller skeleton which can, as the name implies, control various events. It also adds a reference for this controller to the app.js. As we open up the controller file in app/controller/PictureTab.js we can see the predefined config key. The config consists of 2 properties:

  • refs: attaches a key to all components that match the ComponentQuery defined for it. A ComponentQuery is a simple query-type within Sencha Touch to select components rather than HTML elements.
  • control: specifies the events and attached actions for these events.

Let’s have a look how we can make the application trigger an event once we tap one of the pictures.

config: {
       refs: {
           picture: 'img'
       },
       control: {
           'picture': {
               'tap': 'onPictureTap'
           }
   }

In the refs we have placed the line picture: 'img' this defined that every img xtype in our views is referred to as picture in our controller.

In the control section we make use of this reference and attach an object with the property 'tap': 'onPictureTap' this tells the application that we want to take control once an image is tapped. The definition of this control will be placed in the onPictureTap method inside the controller. This brings us to the final step which is implementing the definition. In our controller object definition we add the onPictureTap method. As an example we will show an alert box to the user, which tells the user what the location of this image is. If you’re not bootstrapping anything this is also a good opportunity to remove the launch method.

onPictureTap: function(imageComponent) {
       var src = imageComponent.getSrc();
       Ext.Msg.alert('Event handled', 'You tapped ' + src);
   }

Note that the first argument of this function is the component instance which triggered the event. This way we can use the component’s methods to access it.

Once we reload the app in our browser and tap a picture in the carousel we should see a message with the name of the image in it.

Data binding

Now we know how to control the applications our next concern is working with data. Sencha Touch 2 provides a very complete data handling package which we will utilize in this chapter.

In the image above we can see the main components included in the data package. The Model is a single entity of a ‘thing’ in your application (like a product, user or calendar item), it defines the blueprint of this entity. A Store is a collection of entities commonly used to propagate a list. The Proxy defines the read and write gateways to the data source which holds the data.

Model

If we want to start adding data to our application we will need to define the blueprint of our model first. The model will have certain properties with a data type attached to it (if no datatype is defined Sencha Touch 2 will automatically assign one, this is not advised as this can lead to unexpected results). Let’s define a blueprint for an employee by running the following command from our application root:

sencha generate model Employee id:int,name:string,imgsrc:string

This will create a new file in app/model/ called Employee.js which has the properties we’ve just defined as a key named fields in the object’s config.

Store

Creating a store is not part of Sencha Cmd, just like views, therefor we need to create a new store manually. This gives us a good opportunity to review how we manually add components to our project.

We start off by creating a file called Employees.js in the app/store/ directory. In this file we define the following class:

Ext.define('MyAwesomeApp.store.Employees',{
   extend: 'Ext.data.Store',
 
   config: {
       model: 'MyAwesomeApp.model.Employee',
       autoLoad: true
   }
});

In this class we extend a basic store (Ext.data.Store), which is an abstract implementation. Then we configure the store by telling it that it needs to use the MyAwesomeApp.model.Employee model as the blueprint for it’s data. The second configuration option autoLoad tells the application that the data needs to be loaded upon opening the application.

The final step for defining our store is adding it to our app.js in the root directory of our application. There you add a new property called stores which will define an array of strings with the stores which we are going to use, of course we start off with our Employees store.

stores: [
       'Employees'
   ],

Proxies

The final addition before we can start pulling data and use it in our application is a proxy. Proxies can be attached to both stores and models as a config item. The most common case is that the store will know it’s model class and that the model will have the proxy attached. This gives us the power to use a single model with the proxy rather than having to initiate a collection of models.

The proxy will consist of 2 main items which are a reader and a writer. The scope of this article will just show the reader since they are very similar.
Our proxy will read a static file on the server (resources/employees.json) in our resource folder using AJAX, the following config in our model (app/model/Employee.js) defines this proxy in it’s config:

proxy: {
        type: 'ajax',
        url: 'resources/employees.json',
        reader: {
            type: 'json',
            rootProperty: 'employees'
        }
    }

Sencha Touch 2 comes packed with several proxy-, reader- and writer-types, for this example we are using the proxy type ‘ajax’ and assign the url of the ajax resource which is a JSON file. The next item is a reader which is capable of reading ‘json’ and it inspects the file for a root property named ‘employees’ which will contain an array of (suprise, surprise) employees.

Publishing data through the UI

Once we have the proxy and json file in place we still need a UI element to show the data.
For this we are going to create a new view which will utilize the list component. We create a new file in /app/view/ and call it EmployeeList.js and define our new class in it:

Ext.define('MyAwesomeApp.view.EmployeeList',{
   extend: 'Ext.dataview.List',
   xtype: 'employeeslist',
 
   config: {
       store: 'Employees',
       layout: 'fit',
       styleHtmlContent: true,
       itemTpl: '<h3><img src="{imgsrc}" style="max-height: 40px;">{name}</h3>'
   }
});

The difference we see here between the view we created before and this one is that we extend an other type of component, the list component, and that this component takes different config parameters. What we configure here is the store which points to our Employees store we just created, and the itemTpl. This itemTpl represents how 1 item in the list is supposed to look, the data from the model is added in by placing the property we want to show within curly braces.

Once we have our new view in place we add it to the app.js’s view-array as we did before and we create another tab in our app/view/Main.js

{
        title: 'List',
        xtype: 'employeeslist',
        iconCls: 'photos1'
    }

As we can see this tab will refer to the xtype of our newly created EmployeesList class.
When you reload the app now you can see a new tab in the tab bar which will open up a list instance with all the data in it.

If you want to practice with all we’ve learned up to now it would make sense to attach a non-static data source (like a web-service) and create a simple CRUD app.

Device profiles

Sometimes you can’t get around implementing different features for different type of devices, the most common example is that tablets usually have a whole lot more screen real estate than smartphones. Luckily Sencha Touch 2 has the ability to implement profiles so we can easily extend on existing classes. A good tip is to work from the smallest form factor to the larger ones you’d like to implement.

To start working with profiles we can use the Sencha SDK Tools again with the following command:
sencha generate profile Tablet

And we do the same for a phone profile:

sencha generate profile Phone

This creates the new classes in the app/profile/ directory. The next thing we need to do is specify when a device is a tablet and when a device is a phone. Sencha Touch will look for a method in the profile which is called isActive, this method needs to return a boolean value so the framework knows if the defined profile needs to be used at runtime.

In this example Sencha Cmd detected what we wanted to do and the isActive method is already implemented. If the name of the class isn’t that obvious the isActive method needs to be modified.

Now that our app is aware of the different profiles we can start creating implementations for it. By default the autoloader will append the namespace with the profile name before the actual class name. To clarify this let’s create different views for our list.

We create a new controller in the directory app/controller/tablet called EmployeesList.js and enter the following code:

Ext.define('MyAwesomeApp.controller.tablet.EmployeesList', {
   extend: 'Ext.app.Controller',
 
   config: {
       refs: {
           list: 'list'
       },
       control: {
           'list': {
               'itemtap': 'onItemTap'
           }
       }
   },
 
   onItemTap: function(listItemComponent) {
       Ext.Msg.alert(
           'Tablet info',
           'On a tablet you will get a large info view'
       );
   }
});

Please take note of the class name which now contains tablet in it’s namespace.

The final step is making the app aware of this new class, this time we do not add it to the main app.js but the Tablet.js in the app/profiles/ directory:

controllers: ['EmployeesList'],

If you open up the application on a tablet device now (or a tablet device emulator/simulator) the
defined event will run.

When using a phone emulator you can see that nothing happens when you tap a list item. Now would be the time to practice by implementing a controller which handles these events just for phones.

Theming and styling your application

The default css-theme that comes with Sencha Touch 2 has been heavily influenced by iOS. The good part is that it is also highly customizeable as it is built using Compass (an extension to SASS). You can get the compass compiler running by using the gem installer:

gem install compass

How Compass works is outside of the scope of this article, but for brevity we will highlight a few important things;

  • The extension of a compileable file is .scss
  • With the command compass compile the changes will be compiled to a normal css file which browsers can interpret.
  • With the command compass watch the files in the current directory will be compiled as soon as changes are saved to them.

You may have noticed that in an earlier stage we added an iconCls property but the icon never showed up in your tabbar. This is where we are going to fix that, open the app.scss file under the resources/sass/ directory and add the following line:

@include pictos-iconmask('photos1');

This is a built in function of the Sencha Touch 2 framework to add classes with masked icons. Compile the scss file and the icon should be visible now.

In addition you can also add normal css to this file and it will be compiled into the resulting css file as well.

Some final tips

As you can see Sencha Touch 2 is simple to use, yet very powerful to get your requirements done. Once you start creating your own implementations make good use of the very clear documentation at http://docs.sencha.com.

Always make use of Sencha Cmd whenever it supports what you are doing, it takes away the human error for various things which are easily forgotten.

If you feel uncomfortable with Javascript you can also get Sencha Architect 2 which is an easy IDE for setting up your apps. Eventually you will be expected to do some Javascript so get a book on the subject in the meantime.

Always stay away from putting methods in your views. Even though it is tempting and sometimes the documentation points out the possibility to do so, it is not going to help you. Once you start bug fixing or revisiting your project it will get hard to understand why certain events are happening as they do. Always use the controllers and bootstrapping to define functionality.

    Leave a reply