Tag Archives: senchatouch

Getting Touch-y

At the recent hackathon, I decided to use JQuery Mobile for my application instead of Sencha Touch. I hadn’t played with Sencha Touch for a while, and it isn’t a “casual user” friendly framework, so I was able to be productive on short notice with JQuery Mobile.

Now that Sencha Touch 2 has reached Release Candidate status, I decided to give it a try for another small side project I’ve wanted to do. I kept the backend the same, using NodeJS and Express, but took the time to dive in and learn Sencha Touch 2 at least enough to be productive.

First off, Sencha Touch 2 has really improved in the documentation area. The docs include a lot more examples, and I found the Jog with Friends sample to be the most useful. The API documentation is also much improved. Each of the classes contains sample code so you can quickly see how to use the features.

On the downside, the documentation isn’t 100% consist on how applications are created. For example, the Ext.Map sample uses the trimmed-down Ext.setup() versus the preferred Ext.application() syntax.

One of the best resources for learning the framework is the SenchaLearn Github repository. This has a lot of tutorial and sample applications. Drew Neil also has an excellent collection of sample applications on his repository. His Sencha-Touch-Boilerplate project gives you a great starting point for an application, making development a lot easier. I used this boilerplate for my application and it works great.

The biggest mental hurdle with Sencha Touch 2 was getting my head around how the MVC components interact. It all came together for me when the notion of refs and controls clicked. In a typical Java / Spring Framework application, URLs are mapped to a controller, which then determines the view to render. In a simple Sencha Touch 2 application, that doesn’t have to be the case, and that is what kept throwing me off.

In a Sencha Touch 2 application, you can specify routes that map URLs to controller actions, but that isn’t necessary in a small application. Instead, you load the Viewport with a view, and the controllers are event listeners around the actions in a view.

For example, here’s my app.js file:

Ext.application({
    name: 'Javamug',
 
    controllers: ['Main'],
    views: ['Main'],
 
    launch: function() {
        Ext.Viewport.add({
            xclass: 'Javamug.view.Main'
        });
    }
});

I’m loading up the Viewport with a specific view and that’s it. In this case, my Main view is TabPanel, and it loads up a bunch of tabs. Sencha Touch takes care of rendering the correct view when you click an icon on the tab, which is a nice time saver.

Here’s what the first page looks like:

>

In one of my views, I have two buttons which are defined like this:

{xtype: 'button', ui: 'green-round', text: 'Yes', id: 'attendButton'},
{xtype: 'button', ui: 'red-round', text: 'No', id: 'declineButton'}

Note I added an id attribute to them. This is what makes controllers easy to use. In my Controller, I define the refs and control properties to capture the events from these buttons and call some methods when they are tapped:

config: {
    refs: {
        attendButton: '#attendButton',
        declineButton: '#declineButton'
    },
    control: {
        '#attendButton': {
            tap: 'attendMeeting'
        },
        '#declineButton': {
            tap: 'declineMeeting'
        }
    }
}

The refs section is create some getters for my two buttons. Since I put an ID on the components, I can use that to map them to the friendly names in my controllers. The result is that inside the controller, I can call getAttendButton() and getDeclineButton() from my code to get access to the button directly without having to navigate some contorted hierarchy.

The control section works in a similar way. I’m using the ID of the components, which get mapped back to the components via the ComponentQuery class at runtime. Inside the braces for each button, I’m defining an event listener for the button’s tap event. In this case, tapping the button with ID of attendButton will call the attendMeeting() method in the controller.

Once I quit trying to forcibly shoehorn the controllers into the process, similar to how I would do in Java, and just let them be event handlers, life got easy. I’m still learning the ropes, and I know it is possible to specify URL routes inside the controllers, but I didn’t have a need to do that in my simple application.

The next hurdle was with the Ext.Map component. I wanted a tab which showed the location of our meeting in a Google Map. I beat myself over the head for a whole evening trying get this to work right. It was complicated by the examples not being consistent. The Jog with Friends, Kitchen Sink and Map Demo samples each do things differently. Complexity was compounded by the fact there is a bug with the Release Candidate with rendering maps on TabPanels.

In the end, I finally got it to work by creating the map in the initialize() method of the view and adding it to the Container manually. The code looks like this (after dealing with the bug):

Ext.define('Javamug.view.Map', {
    extend: 'Ext.Container',
    xtype: 'mapcard',
 
    requires: [
    	'Ext.Map'
    ],
 
    config: {
        iconCls: 'locate',
        title: 'Location',
        layout: 'fit',
 
        items: [
            {
                ui: 'light',
                docked: 'top',
                xtype: 'toolbar',
                title: 'Location'
            }
        ]
    },
 
    initialize: function() {
 
        this.callParent();
 
        var position = new google.maps.LatLng(32.9770421, -96.8270373);
 
        var infowindow = new google.maps.InfoWindow({
                content: 'Improving Enterprises<br/>Addison, TX 75001'
        });
 
        var map = Ext.create('Ext.Map',{
            mapOptions : {
                zoom : 14,
                mapTypeId : google.maps.MapTypeId.ROADMAP,
                navigationControl: true,
                navigationControlOptions: {
                    style: google.maps.NavigationControlStyle.DEFAULT
                }
            },
 
            listeners: {
                maprender: function(comp, map) {
 
                    var marker = new google.maps.Marker({
                        position: position,
                        title : 'Improving Enterprises',
                        map: map
                    });
 
                    google.maps.event.addListener(marker, 'click', function() {
                        infowindow.open(map, marker);
                    });
                }
            }
 
        });
 
        map.setMapCenter(position);
        this.add(map);
    }
});

The mapConfig section was a major pain too. Normally, you can specify a center property which contains the LatLong of where you want to center the map. Except it doesn’t work. My desired center kept popping up just out of view in the top left corner. I finally removed the property from the config and just manually called the setMapCenter() method of the Ext.Map component and that worked.

One thing I don’t like about Sencha Touch is how it handles pages which are mostly HTML text. Stuffing a bunch of HTML markup into the html config element isn’t an elegant solution. Fortunately, the Oreilly demo app has a good way of solving this. They create a new panel which takes a URL in the config and uses the initialize() method to load the content for the URL. The code looks like this:

Ext.define('Javamug.view.Meeting', {
    extend: 'Ext.Container',
    requires: ['Ext.Ajax'],
 
    config: {
        iconCls: 'calendar2',
        title: 'Meeting',
        styleHtmlContent: true,
        scrollable: 'vertical',
        url: 'current.html',
        items: [{
            ui: 'light',
            docked: 'top',
            xtype: 'toolbar',
            title: 'Java MUG'
        }]
    },
 
    initialize: function() {
 
         Ext.Ajax.request({
            url: this.config.url,
            success: function(rs) {
                this.setHtml(rs.responseText);
            },
            scope: this
        });
    }
});

Using this technique, I could use a Jade template in Express to create the “static” content rather than pack it all into the JavaScript view file.

Outside the complexity, there are two downsides to using Sencha Touch. First is theming. This blog post provided the most help in figuring out how theming works. Using the Bootstrap template above also make life a lot easier because it starts with the app.scss and config.rb in the right place and includes instructions in the README.md file on how to compile them.

The second downside is size: Sencha Touch is not a light-weight framework. My CSS, combined app-all.js and framework files came in around 700K for a simple application. I could trim things down by eliminating some of the includes on the theme, but that is still pretty large. By comparison, in my JQuery Mobile application, the framework files came in around 250K in size.

The tradeoff for the larger size is being able to use a sophisticated client-side MVC framework with great looking, and performing, components.

Sencha Touch 2 is a big win for me. I want to work on the file size, but now that I have a feel for the framework, I’m expecting my learning to pick up. I’ll hopefully get a chance to give a whirl on a larger application soon.

The Sencha guys have really knocked it out of the park with Sencha Touch 2. It is, without a doubt, the most sophisticated and polished mobile JavaScript framework out there right now.