Today we are going to create a mobile weather app with Sencha Touch 2.1 and we will pull the weather data in xml format using YQL, Yahoo Query Language with Sencah Touch 2.1’s proxy feature.  Lets get started.

To build this app, we need three views and a controller.  The first view serves as a container and in it the second view appears as a form is defined for user to enter a city name to get her current weather condition.  The last view serves as a template where the weather result is presented. If more than one result is returned, there will be multiple views and will be arranged in carousel format.  And finally the controller is there to get user’s input,  form a query to ran against YQL service, add the result to the view template and then push the result set on top of the form.



Step 1: Create a form view for user to enter a city name

1.1 Lets declare the view a form panel, then add a text field and a button in the items definition

1.1.1 under app/view, create a file called WeatherForm.js and tell it to load the Weather form and the Weather view

	requires: [ 
	           'demo.view.WeatherForm',
	           'demo.view.Weather'
	]

1.1.2 create a form panel

extend: 'Ext.form.Panel'

1.1.3 in the config section, create 2 items:

{
xtype: 'textfield',
name: 'wLocation',
label: 'Location'
}

and

{
xtype: 'button',
text: 'Get Weather',
action: 'wButton'
}

Step 2: Create a navigation view to show the form

Note: A navigation view is a card layout and only the top most card is visible. To manipulate the cards, we can use the object’s push and pop method.

2.1 under app/view, create a file called WeatherContainer.js

2.2 We need to tell the framework, this view is a navigation view

extend: 'Ext.navigation.View'

2.3 Then we need create our app entry point which is the weather form we created at step 1.

Lets load the view first

requires: [ 'demo.view.WeatherForm' ]

then add the form as one of the items

xtype: 'weatherform'

 

Step 3: Create a template view for the result

3.1 under app/view, create a file called Weather.js

3.2 We want this to be a panel.  Later on we will create this dynamically in the controller and then “push” it on top of the form, more on that later.

declare it as panel

extend: 'Ext.Panel'

in the config, add this.  This is the template where the weather data will be inserted into the placeholder as indicated by the variables enclosed by curly braces. In this case, {title}, {subtitle}, {itemdescription}.

config: {
		layout: 'fit',
		padding: '0.5em',
		tpl: '<h1>{title}</h1><div>{subtitle}</div><div>{itemdescription}</div>'
	}

Step 4: Create a model for the weather data returned from Yahoo

4.1 under app/model, create a file called WeatherModel.js

4.2 we need to extend from Model

extend: 'Ext.data.Model'

A model is where you declare the data structures and their relationship.  Since this is a rather simple model, you can think of a model as a table as in the relational database.  And in our model, we define fields (or columns in database).

The output we are getting from YQL contains lots of xml tags.  Among the many, we are only interested in 3 of them.  First is the very first title tag.  The second is the title tag immediately under the item tag and this relation is indicated in the mapping option.  Notice we use the greater than sign to show the relationship.  On the left hand side is the parent and on the right we have its child.  And we name this field “subtitle”.  The last field is the itemdescription which is the description tag under the item tag.

And here is how the template config looks like:

    config: {
        fields: [ {name: 'title'},
                  {name: 'subtitle', mapping: 'item > title'},
                  {name: 'itemdescription', mapping: 'item > description'}
        ]
    }

 

Step 5: Create the controller to handle the input/output

In order to make the application interact with the user, we need to define our actions in the controller.  For this app, we want to (a) get the data from the form (b) take action when the button is pressed (c) fetch the data (d) create a panel for each result and push it to the navigation view

5.1 under app/controller, create a file called WeatherController.js

5.2 declare it as a controller,

extend: 'Ext.app.Controller'

5.3 we want to tell the app to get the form data and the weathercontainer to which to load the weather results into.  Lets add a few references in our “refs section” under config.

config: {
   refs: {
      wform: '#weatherFormPanel',
      weathercontainer:'weathercontainer'
   }
}

Note: wform is the name we would like to use in our controller to refer to the textfield whose name is wLocation in the weather form.

5.4 Lets get the form data and store it in a variable

   var values = this.getWform().getValues();

Note: the getWform() is a magic from Sencha Touch.  Whatever defined in refs will get its setter/getter method and you can tell ST use the word “get” and then append to it the refs name to form the getter method name, in this case, “getWform()”. Notice the first letter of the refs name is capitalized?

5.5 Lets create a store to fetch the data from yahoo.

   var weatherStore = Ext.create("Ext.data.Store", {
	                  autoLoad: true,
	                  model: 'demo.model.WeatherModel',
	                  proxy: {
	                           type: 'ajax',
	                           url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%20in%20(select%20woeid%20from%20geo.places%20where%20text%3D%22" 
	   				+ values.wLocation  + "%22)",	
	                           reader: {
	                                   type: 'xml',
	                                   record: 'channel',
	                                   rootProperty: 'results'
	                           }
			    }
		        });

Note: We want the store to call the load method upon its creation (autoload: true).  And we need to associate a model to this store.  In the proxy section, we tell the framework to use Ajax and ask it to load the data from the url.  The reader is tell what the data format is, which tag will enclose each record(channel) and which is the root tag (results).

5.6 Since we have autoLoad set to true, the following load method will be called.

weatherStore.load(function(records, operation, success) {
								if (records != "") {
									var weatherCarousel  = Ext.create("Ext.Carousel", {
										title: 'Weathers ',
										iconCls: 'action'
									});

									for (var i=0; i<records.length; i++) {
										var weatherPanel = Ext.create("demo.view.Weather");
										weatherPanel.setData(records[i].getData());
										weatherCarousel.add(weatherPanel);
									}
									this.getWeathercontainer().push(weatherCarousel);
								} else {
									alert('Location "' + values.wLocation + '" : not found!');
								}
						}, this		
					);

 

Note: First we check if there is any record returned from the proxy, if we do, we create a “Carousel” to hold the results otherwise we use an alert to tell the user the location is not found.  If there are multiple cities in different states/countries, the user will be able to swipe through the results.  Then we create a “Weather” view, set the data and then add this view to the “Carousel”.  Once all views are added, we push the “Carousel” to the WeatherContainer.  Notice we again take advantage of the getter method created for us by ST when we defined our object in the refs section.

6.  Tell the app we have the views, a model and a controller created.

6.1 vi app.js and the add the following:

controllers: ['WeatherController'],
models: ['WeatherModel'],
views: ['WeatherContainer']

7. Add the container to the Main view

requires: [ 'demo.view.WeatherContainer' ]
items: [
   {
      xtype: 'weathercontainer'
   }
]

8. Done.

Weather Main Page

 

Get Seattle Weather

Seattle WA Weather Result

 

Seattle MX Weather Result