Tutorial 3: Sencha Weather App – add 2 tab panels with List component, itemTpl

SenchaTouch_Preview

  • In tutorial 1 we created the sample Sencha Touch App
  • In tutorial 2 we edited the sample app to contain 2 tab panels.

In this tutorial 3 we will finish the 2 tab panels.

  • List component
  • Attached to the store
  • itemTpl

List Component

A list of items, with touch swipe of scrolling.

Store

A sencha touch store is the data source of you objects. These could be stored in HTML5 Local storage, memory or proxied to web servies.

The list component allows us to easily attached a store to a list. This allows us to populate the list items for a data source. This is all sorts of powerful.

itemTpl

We want to style each list of our List Component with our own HTML template. This is there the itemTPL comes in. As you can guess it’s the item template for the list component.

Ext.define('WeatherApp.view.Weather', {
    extend:'Ext.List',
    xtype:'weather',

    /* Configure the tab here */
    config:{
        title:'Weather', //title on the tab button
        iconCls:'locate', //icon on the tab button

        disableSelection: true,

        /* attach this list component to the weather store */
        store:'Weather',

        /* create a title bar for the tab panel */

        items: [
            {
                docked: 'top',
                xtype:'toolbar',
                title:'Weather',
                id: 'mainToolbar',
                cls: '',
                items: [

                    { xtype: 'spacer' },
                    {
                        xtype: 'button',
                        cls: 'refreshWeather',
                        iconCls: 'refresh',
                        id: 'refreshWeather'
                    }

                ]
            }
        ],

        /* markup for the data returned from the store */
        itemTpl:Ext.create('Ext.XTemplate',
            '</pre>
<div>',
 '
<h2>{name}, {[values.sys.country]}</h2>
',
 '
Time: {[this.timeFormat(new Date())]}

',
 '
Weather: {[values.weather[0].description]}

',
 '<img alt="" src="' + WeatherApp.app.openweatherimages + '{[values.weather[0].icon]}" />',

 '
Temperature: {[values.main.temp]} ℃

',
 '
Humidity: {[values.main.humidity]} %

',
 '
Min Temp: {[values.main.temp_min]} ℃

',
 '
Max Temp: {[values.main.temp_max]} ℃

',
 '</div>
<pre>',
            {
                timeFormat:function (date) {

                    var days = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'];
                    var newDate = date;

                    return days[newDate.getDay() - 1] + " "
                            + newDate.getHours() + ":"
                            + newDate.getMinutes() + ":"
                            + newDate.getSeconds();
                }
            }
        )
    },

    initialize:function () {
        this.callParent();
    }

});

Points of interest:

The Weather Store that supplies the List Component.

The placeholders in the itemTpl I.E. {name)

The next step for us:

  • We need to get the Weather Data from somewhere. We’ll sign up for the free Open Weather Map API
  • Create the Model to describe the data return the from Open Weather Map API
  • Create the Store to hold the above modelled objects.

Stay tuned for Tutorial 4.

CODE HERE:

You can clone to the branch and browse to the app to see the two tabs in action.

https://github.com/jamiegood/WeatherApp/tree/TwoPanelTabs

Tutorial 2: Sencha Weather App – add 2 tab panels

In the first tutorial we created a simple Sencha Touch application using the Sencha CMS tools.This gave us a sample working application to explore.  Now we will update this, removing what is not necessary all the while keeping with the MVC pattern.

Plan:

  1. Create 2 tab panels
  2. One which is eveualtyy show the weather report.
  3. The second for a ‘settings’ type page.

1. Create the Main view to hold the tab panels

/*
This file is generated and updated by Sencha Cmd. You can edit this file as
needed for your application, but these edits will have to be merged by
Sencha Cmd when it performs code generation tasks such as generating new
models, controllers or views and when running "sencha app upgrade".

Ideally changes to this file would be limited and most work would be done
in other places (such as Controllers). If Sencha Cmd cannot merge your
changes and its generated code, it will produce a "merge conflict" that you
will need to resolve manually.
*/

// DO NOT DELETE - this directive is required for Sencha Cmd packages to work.
//@require @packageOverrides

//
Ext.Loader.setPath({
    'Ext': 'touch/src',
    'WeatherApp': 'app'
});
//

Ext.application({
    name: 'WeatherApp',

    requires: [
        'Ext.MessageBox'
    ],

    views: [
        'Main',
        'About',
        'Weather'
    ],

    icon: {
        '57': 'resources/icons/Icon.png',
        '72': 'resources/icons/Icon~ipad.png',
        '114': 'resources/icons/Icon@2x.png',
        '144': 'resources/icons/Icon~ipad@2x.png'
    },

    isIconPrecomposed: true,

    startupImage: {
        '320x460': 'resources/startup/320x460.jpg',
        '640x920': 'resources/startup/640x920.png',
        '768x1004': 'resources/startup/768x1004.png',
        '748x1024': 'resources/startup/748x1024.png',
        '1536x2008': 'resources/startup/1536x2008.png',
        '1496x2048': 'resources/startup/1496x2048.png'
    },

    launch: function() {
        // Destroy the #appLoadingIndicator element
        Ext.fly('appLoadingIndicator').destroy();

        // Initialize the main view
        Ext.Viewport.add(Ext.create('WeatherApp.view.Main'));
    }

});

See the highlighted lines above for the changes.
Create the main view file – app/view/Main.js

Ext.define('WeatherApp.view.Main', {
    extend:'Ext.tab.Panel',
    xtype:'main',

    config:{

        tabBarPosition:'bottom',
        defaults:{
            styleHtmlContent:true
        },
        items:[
            {
                xtype: 'weather'
            },
            {
                xtype:'about'
            }
        ]
    }
});

This view extends the Sencha Touch component, the Tab Panel. Take note of:

  • xtype: this is a shortcut we will use to refer to this Main view. Note that we have already referenced the ‘main’ xtype in our app.js above.
  • The config parameter: This is the configuration for the Panel Component – importantly not the individual panels.
    A huge amount of configuration options exist. Refer the the Sencha Touch API and the Sencha Touch Examples that are downloaded with the Sencha Touch SDK.
  • Components often have required config parameters that must be set.  The above are the minimum required for the Ext.tab.panel component.

Step 2: Create A view for the About Tab panel

See Items in the app/view/Main.js – theses will be an array of the tabs themselves. If I have 3 items there we would have 3 tab panels.

Our second tab item is referenced by an xtype ‘about’. Think of an xtype as a shortcut to the About view.  We’ll start with that as it’s simpler than the Weather view 🙂

Firstly we have the views already added out our app.js. Lines 30 – 33 above. Good times.

We’ll need to create a view file – app/view/About.js

We’ll keep it simple for now and just have some text.

Ext.define('WeatherApp.view.About', {
    extend: 'Ext.Container',
    xtype: 'about',

    /* Configure the tab here */
    config: {
        title: 'About',
        iconCls: 'settings',

        /* Create a title bar for the tab panel */
        items: {
            docked: 'top',
            xtype: 'titlebar',
            title: 'About'
        }
    },

    /*contents of tab */
    html: 'The about page'

});
so whats happening here? Notice the following:
This view extends Ext.container component – this is a general component. Fine if you just want to add some text like we have here.
Xtype is ‘about’. We are giving this component a shortcut name called ‘about’. The Main view pulls in this view via this xtype.
More config for the Ext.tab.panel.
Items again for the panel, this time using a built in xtype for a titlebar component.
Again the the Sencha API is your best bet for figuring out about these little have very powerful configuration components.
Ignore the other config for now. The are default parameters to be cover in a latter tutorial (I hope).

Step 3: Create a View for the Weather Tab panel

Create a app/view/Weather.js view for the ‘Weather’ xtype referenced from your Main view.

Ext.define('WeatherApp.view.Weather', {
    extend:'Ext.List',
    xtype:'weather',

    /* Configure the tab here */
    config:{
        title:'Weather', //title on the tab button
        iconCls:'locate', //icon on the tab button

        disableSelection: true,

        /* attach this list component to the weather store */
        store:'Weather',

        /* create a title bar for the tab panel */

        /*
items:{
docked:'top',
xtype:'titlebar',
title:'Weather'
},
*/

        items: [
            {
                docked: 'top',
                xtype:'toolbar',
                title:'Weather',
                id: 'mainToolbar',
                cls: '',
                items: [

                    { xtype: 'spacer' },
                    {
                        xtype: 'button',
                        cls: 'refreshWeather',
                        iconCls: 'refresh',
                        id: 'refreshWeather'
                    }

                ]
            }
        ],

        /* markup for the data returned from the store */
        itemTpl:Ext.create('Ext.XTemplate',
            '<div class="">',
            '<h2>{name}, {[values.sys.country]}</h2>',
            '<p>Time: {[this.timeFormat(new Date())]}</p>',
            '<p>Weather: {[values.weather[0].description]}</p>',
            '<img src="' + WeatherApp.app.openweatherimages + '{[values.weather[0].icon]}"/>',

            '<p>Temperature: {[values.main.temp]} ℃</p>',
            '<p>Humidity: {[values.main.humidity]} %</p>',
            '<p>Min Temp: {[values.main.temp_min]} ℃</p>',
            '<p>Max Temp: {[values.main.temp_max]} ℃</p>',
            '</div>',
            {
                timeFormat:function (date) {

                    var days = ['Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat', 'Sun'];
                    var newDate = date;

                    return days[newDate.getDay() - 1] + " "
                            + newDate.getHours() + ":"
                            + newDate.getMinutes() + ":"
                            + newDate.getSeconds();
                }
            }
        )
    },

    initialize:function () {
        this.callParent();
    }

});

Suddenly it’s become a lot more complicated.

Points of interest that we spoken about already

Again this view extends a component, a new component called List. Can you imagine what that does?

  • xtype is ‘Weather’. This component is included in the Main.js view via this xtype
  • Config parameter for configuring this tab
  • An Items parameter that has something to do with a toolbar at the top of the View

New stuff:

  • A store called Weather
  • The list component
  • itemTpls

We’ll cover all this in the next tutorial.

Code here:

You can clone to the branch and browse to the app to see the two tabs in action.

https://github.com/jamiegood/WeatherApp/tree/TwoPanelTabs

The Way of Testivus

20130309-122023.jpgIf you write code, write tests.
Don’t get stuck on unit testing dogma.
Embrace unit testing karma.
Think of code and test as one.
The test is more important than the unit.
The best time to test is when the code is fresh.
Tests not run waste away.
An imperfect test today is better than a perfect test someday. An ugly test is better than no test.
Sometimes, the test justifies the means.
Only fools use no tools.
Good tests fail.

The Way Of Testivus