Sencha Inc. | HTML5 Apps

Blog

Architecting your app with Sencha Touch 2 MVC, Part 4

May 21, 2012 | Tommy Maintz

In the previous series of articles Part 1, Part 2, and Part 3, we explored architecting a Pandora-style application using the new features of Ext JS 4. We started by applying the Model-View-Controller architecture to a complex UI that has multiple views, stores and models. We looked at the basic techniques of architecting your application, like controlling your views from Controllers and firing application-wide events that controllers can listen to. We also discussed how to get references to views, controllers, models and the application itself. Lastly, we implemented several controllers to get a feel for how to implement basic application logic.

In Sencha Touch 2, we introduced the newest iteration of our MVC architecture. Based on the same concepts found in the Ext JS 4 and Sencha Touch 1 MVC package, we have simplified existing features like control and reference syntaxes and introduced new functionality like routes and history support.

In this article, we will take the existing code we have created and upgrade it to use Sencha Touch 2 and the updated application architecture. We will discuss some of the differences in syntax and talk about some of the new concepts to consider. At the end of this article, you should be better prepared to go into your existing app Sencha Touch 1 app and upgrade it to Sencha Touch 2, provided it is architected based on the principles discussed in the previous articles.

Ext.application

Initializing your application has remained much the same compared to Ext JS 4. Controllers, views and models are included the same way, and you continue to define the launch and init methods. For a detailed overview of the capabilities in the new application object, I suggest you read the following http://docs.sencha.com/touch/2-0/#!/guide/apps_intro guide. We used used autoCreateViewport in our app which has been deprecated. You are now expected to instantiate your main view. The following code shows how we instantiate our Main view in the launch method.

/app/app.js

Ext.application({
    name: 'Pandora',

    views: ['Main'],
    models: ['Station', 'Song'],
    stores: ['Stations', 'RecentSongs', 'SearchResults'],
    controllers: ['Station', 'Song'],

    launch: function() {
        Ext.create('Pandora.view.Main');
    }
});

The config object

In Sencha Touch 2, we are fully relying on the class system’s config system. This not only has several benefits to the frameworks code base but also for your application code. It makes your views, controllers and models more consistent and predictable. I recommend reading the http://docs.sencha.com/touch/2-0/#!/guide/class_system guide, as it thoroughly explains the capabilities of the class system, including the configuration system.

Views

So let’s start by converting our Main view to the new config system.

app/view/Main.js

Ext.define('Pandora.view.Main', {
    extend: 'Ext.Container',

    requires: [
        'Pandora.view.NewStation',
        'Pandora.view.SongControls',
        'Pandora.view.StationsList',
        'Pandora.view.RecentlyPlayedScroller',
        'Pandora.view.SongInfo'
    ],

    config: {
        fullscreen: true,
        layout: {
            type: 'hbox',
            align: 'stretch'
        },
        items: [{
            docked: 'top',
            xtype: 'toolbar',
            height: 80,
            items: [{
                xtype: 'newstation',
                width: 150
            }, {
                xtype: 'songcontrols',
                flex: 1
            }, {
                xtype: 'component',
                html: 'Pandora<br>Internet Radio'
            }]
        }, {
            width: 250,
            xtype: 'panel',
            id: 'west-region',
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            items: [{
                xtype: 'stationslist',
                flex: 1
            }, {
                html: 'Ad',
                height: 250,
                xtype: 'panel'
            }]
        }, {
            xtype: 'container',
            flex: 1,
            layout: {
                type: 'vbox',
                align: 'stretch'
            },
            items: [{
                xtype: 'recentlyplayedscroller',
                height: 250
            }, {
                xtype: 'songinfo',
                flex: 1
            }]
        }]
    }
});

The first thing to note is that we are extending Ext.Container instead of Ext.Viewport. In Sencha Touch 2, there is always a Viewport instantiated. It takes up the full screen by default and uses the card layout. By defining the fullscreen property on a component, it will automatically be added to this Viewport.

We also see that we have defined all of our item configurations inline in the config block. In Ext JS, we have always required that you define any complex configurations (Objects and Functions) inside the initComponent method. This was required because we needed a unique copy of these complex objects in each prototype. However, the class system in Sencha Touch 2 will deeply merge the config block when you create a subclass. This allows the View files to become cleaner and easier to understand.

Since our current app was written for Ext JS, and Sencha Touch has some minor differences in item configurations, it is also useful to note that dockedItems has been deprecated and you are able to just define docked items inside the items collection. The docked configuration will allow you to dock any item to any side of the container.

I won’t go into the details of each View definition in this article, but you can browse through the attached source code to see the changes I had to make to convert the Views from Ext JS to Sencha Touch 2.

Stores and Models

Even though the data package has been updated to use the configuration system, and in the process has been entirely refactored and cleaned up, the API has stayed identical to Sencha Touch 1 and Ext JS 4. This means that in order to update our Stores and Models, we only have to worry about moving all the configurations into the config blocks. Here are the Station model and the Stations store after making these changes.

app/model/Station.js

Ext.define('Pandora.model.Station', {
    extend: 'Ext.data.Model',

    config: {
        fields: ['id', 'name'],

        proxy: {
            type: 'ajax',
            url: 'data/stations.json',
            reader: {
                type: 'json',
                rootProperty: 'results'
            }
        }
    }
});

app/store/Stations.js

Ext.define('Pandora.store.Stations', {
    extend: 'Ext.data.Store',
    requires: 'Pandora.model.Station',

    config: {
        model: 'Pandora.model.Station'
    }
});

Controllers

So far we have looked at Views, Stores and Models. Although there are minor differences in these elements between Ext JS 4 and Sencha Touch 2, most of the new functionality and syntax has been introduced in the Controllers. Let’s start by converting one of our existing controllers to the new syntax and discuss the changes.

    Ext.define('Pandora.controller.Station', {
        extend: 'Ext.app.Controller',

        config: {
            stores: ['Stations', 'SearchResults'],

            refs: {
                stationsList: 'stationslist',
                newStationSelect: 'newstation'
            },

            control: {
                stationsList: {
                    select: 'onStationSelect'
                },
                newStationSelect: {
                    change: 'onNewStationSelect'
                }
            }
        },

        launch: function() {
            console.log(this);
            debugger;
            var stationsStore = Ext.getStore('Stations');
            stationsStore.on({
                load: 'onStationsLoad',
                scope: this
            });
            stationsStore.load();
        },

        onStationsLoad: function() {
            var stationsList = this.getStationsList();
            stationsList.select(0);
        },

        onStationSelect: function(list, record) {
            // Fire an application wide event
            this.getApplication().fireEvent('stationstart', record);
        },

        onNewStationSelect: function(field) {
            var station = field.getRecord(),
                store = Ext.getStore('Stations'),
                list = this.getStationsList();

            if (station && !store.getById(station.getId())) {
               store.add(station);
            }
            list.select(station);
        }
    });

References

As you can see, the syntax for references has slightly changed. The old refs block looked like the following.

refs: [{
    ref: 'stationsList',
    selector: 'stationslist'
}]

The refs value has changed from being an array to being an object. Each key in the object represents the name of the references and the value is the ComponentQuery. In the previous articles, we also explained how you can leverage autoCreate and forceCreate to automatically create instances of the components you are selecting if they don’t exist on the page yet. In the new syntax, you could achieve that by doing the following.

refs: {
    stationsList: {
        selector: 'stationslist',
        autoCreate: true
    }
}

The value here becomes a configuration object where the selector is your ComponentQuery.

Controlling views

Another thing to note is the new control config. Instead of defining your view control listeners inside the init method like we did previously, we now define these listeners directly as part of the controller configuration. Let’s have a look at the old {Sencha Touch 1?} control code.

init: function() {
    this.control({
        'stationslist': {
            selectionchange: this.onStationSelect
        },
        'newstation': {
            select: this.onNewStationSelect
        }
    });
}

It’s possible for this logic to be moved into the controller configuration because the listener functions can now be simply referenced as strings. The keys in the control object can still be strings, in which case we assume they are component queries. We did however add the capability to use the reference that you have set up in the refs block. We did this because we saw that people had to write out the same component query most of the time both for setting up a reference and actually controlling an event for the same view referenced.

Getters

In the Ext JS 4 controller class, we automatically generated getters for any stores, models and controllers defined in the controller’s configuration. However, we have found that generating these getters can be quite expensive at the start of the application, so we have deprecated this automatic generation for Store, Model and Controller getters. We still generate the getters for all of the defined references in the refs configuration. To get a reference to a store, you should use the Ext.getStore() method. Models can be referenced by just using the class name. For example, to call a static method on the Station model we could just use Pandora.model.Station.someStaticMethod(). A controller can be retrieved by calling this.getController().

Also, instead of referencing the application instance by using this.application, you should now use the getter this.getApplication(). This is useful when binding to or firing application-wide events.

Summary

In this part of the series, we looked at the differences between Ext JS 4 and the new Sencha Touch 2 application framework. We’ve reviewed some slight differences in syntax, some deprecated functionality, as well as new functionality in Views and Controllers.

There are 19 responses. Add yours.

Laurence Rochfort

2 years ago

Hi,

Could you please provide links to each part of this article?

Many thanks,
Laurence.

Steffen Hiller

2 years ago

Is that new in ST 2.0.1 final that you can use autoCreate without specifying an xtype?
Didn’t work till 2.0.1rc.

(btw, there’s a console.log and debugger in the station controller launch method.)

JD Elliott

2 years ago

Another vote for links to past articles. Searching the blog doesn’t bring up these articles. Thanks!

John Storey

2 years ago

+1 Links to other blog articles. Cannot find them on site search.

Doug Millasich

2 years ago

Whoops.

Just saw that the links for the article are specific to EXT JS. One espresso short of a semi-functional brain. Sorry -

I too would like to have access to the fabled parts one, two and three of this article.

JD

2 years ago

Where are the links to the first 3 parts of this series?

Doug Millasich

2 years ago

ummm. I was right the first time. The first three installments to the series was for Ext JS 4. Just like it says, in the first sentence of the first paragraph.

CE

2 years ago

What about an updated sourcecode for download?

JW

2 years ago

> To get a reference to a store, you should use the Ext.getStore() method.

Is this really a good practice to encourage? It means all your data stores are essentially global variables, and could be modified in any function. This can make it hard to test and debug.

Worth Lutz

2 years ago

Will the noted differences in Touch 2 and Extjs 4 be made consistent in the future?

Mishka Samoylov

2 years ago

Great! But where is the source?

Steven

2 years ago

+1 For being consistent with these changes in ExtJs in the future!

???? ????? ?????

2 years ago

+1 Links to other blog articles. Cannot find them on site search.

Ankit

2 years ago

Nice article,
but where is source code ??

Is there any article to learn Sencha touch from scratch ?

Computerz101

2 years ago

Thanks for the code references that really helps. Is there a part 5 or this this the last of the 4 parts?

Don

2 years ago

A zip of the result would be super helpful for those of us trying to follow along at home

iplaytheme

2 years ago

Hello
I’m a french developper and I have a problem in your theme.
I should want to know if your theme is compatible with menu and sub-menu for pages and category.
I created 3 pages menu and 3 of them have sub-menu. But when I put my mouse on them, I never see the sub-menu.
You can see that here : http://iplaytheme.com/
Under Association, there are 3 other pages. But it is not possible to see them.
Have you a solution for me?
Excuse me for my bad english, I hope that you understand me.
Gretaings.

???

2 years ago

??~

Comments are Gravatar enabled. Your email address will not be shown.

Commenting is not available in this channel entry.