+40 745 232 788

Online Solutions Development Blog   |  

RSS

Creating a Sencha Touch MVC application from scratch, part 4

posted by ,
Categories: Mobile Development
Taggs , , , , , , ,

In this final part of Creating a Sencha Touch MVC application from scratch series we’ll add some data to our application we’ve started in part 1, part 2 and part 3.

Before we start please note that in order for the examples in this article to work, you need to place the application on a web server because we’ll use AJAX to access our data.

Let’s add some news to our application.

Before adding news to our application, we must define first what is actually a news item, what properties does it have. We’ll do this by creating a Model.

Creating a Model

“A Model represents some object that your application manages. For example, one might define a Model for Users, Products, Cars, or any other real-world object that we want to model in the system.” (from Sencha Touch docs)

We’ll create our news item model in app/models/, so create a file named NewsItemModel.js with the following content:

Ext.regModel('NewsItem', {
	fields: [
		{name: 'title', type: 'string'},
		{name: 'date', type: 'string'},
		{name: 'content', type: 'string'}
	]
});

Include the newly created model file in index.html, above the controllers.

As you can see, a model is created using the Ext.regModel function. We pass to it the name of the model and a configuration object as parameters. In the configuration object we define our model properties in the fields array. Each property is an object in which we can set a name and a type.

Our NewsItem model has three properties (title, date and content) with the type set to string. The type property can also be an int, a float, a boolean or it can be set to auto. Sencha Touch will automatically convert each property value to the type set. When no conversion is wanted, the type can be set to auto.

The model property object can also have a defaultValue set.

Now that we have a Model, we need to create a Store.

Creating a Store

“The Store class encapsulates a client side cache of Model objects. Stores load data via a Proxy, and also provide functions for sorting, filtering and querying the model instances contained within it.” (from Sencha Touch docs)

The Store for our news item model will be created in app/stores/ and will be placed in a file named NewsItemsStore.js with the following content:

Ext.regStore('NewsItems', {

    model: 'NewsItem',

    proxy: {
        type: 'ajax',
        url : 'app/data/news.json',
    },

    autoLoad: true
});

Include the newly created file in index.html, after the models:

<!-- MODELS -->
<script src="app/models/NewsItemModel.js" type="text/javascript"></script>

<!-- STORES -->
<script src="app/stores/NewsItemsStore.js" type="text/javascript"></script>

The Ext.regStore function is used for the creation of a store and, similar to regModel, we pass to it the name of the store and a configuration object.

Since a store is a collection of model instances, we must tell what type of objects will be in it, so we’ll set the model property in the configuration object to be our NewsItem. The source of the data and will be defined in a proxy configuration object.

“Proxies are used by Stores to handle the loading and saving of Model data. Usually developers will not need to create or interact with proxies directly.” (from Sencha Touch docs)

Two properties are required when we define a proxy object: the type and the url of the request responsible with data retrieval. For our NewsItems store we’ll use an ajax request and a url pointing to a JSON news file, since the default format of the expected request result is JSON.

Since we want our news to be loaded as soon as possible automatically, we’ll set the autoLoad property of the store config object to true.

Now, let’s create the news.json file in app/data/ and add some news from Sencha Touch Press:

[
    {
    	"title": "Beyond jQuery: JavaScript Tools For The HTML5 Generation",
    	"date": "November 09, 2011",
    	"content": "One of the stated goals of HTML5, at least for some groups, is to replace the Flash plug-in, the gold standard for making sprites and letters dance across the screen."
    },
    {
    	"title": "What Is the Best Mobile Platform for HTML5 Development?",
    	"date": "November 10, 2011",
    	"content": "The focus of the mobile world has turned to HTML5. Right now, HTML5 is positioning itself to be the No. 3 mobile platform behind Apple's iOS and Google's Android and we will see that evolution take place over the next couple of years."
    },
    {
    	"title": "No Flash? No Problem",
    	"date": "November 18, 2011",
    	"content": "So what does the future hold for Flash? I imagine Flash eventually being used more as a creative tool than a delivery format. As Adobe continues to put more effort into exporting HTML5-ready assets from Flash Pro, it tells me the swf may be slowly dying for desktop, too."
    },
    {
    	"title": "Adobe Flash Sites Rapidly Converted To HTML5 For iOS users",
    	"date": "November 21, 2011",
    	"content": "A developer using Sencha Touch reports that translating large existing websites built with Adobe Flash to HTML5 mobile sites accessible to iOS users can now be performed by 1 or 2 people in just three weeks."
    }
]

Using a List to display Store data

Next we’ll display our news.

Open HomeIndexView.js and add a new link:

html: '<a href="#News/index" class="menu-item">News</a>' +
      '<a href="#Home/about" class="menu-item">About</a>',

Create a new controller for handling the news (NewsController.js):

Ext.regController('News', {

    // index action
	index: function(options)
    {
        if ( ! this.indexView)
        {
            this.indexView = this.render({
                xtype: 'NewsIndex',
            });
        }

        var backBtn = this.application.viewport.query('#backBtn')[0];
        backBtn.show();

        backBtn.setHandler(function()
		{
        	Ext.dispatch({
        	    controller: 'Home',
        	    action: 'index',
        	    historyUrl: 'Home/index',
        	    //
        	    animation: {
        	        type: 'slide',
        	        reverse: true,
        	    },
        	});
		});

        this.application.viewport.setActiveItem(this.indexView, options.animation);
    },
});

Now the news controller index view (NewsIndexView.js):

App.views.NewsIndex = Ext.extend(Ext.List, {
    store: 'NewsItems',
    itemTpl: '{title}, <span class="date">{date}</date>',
});
Ext.reg('NewsIndex', App.views.NewsIndex);

As you can see we’ve used the Ext.List component for displaying the news.

The list component requires two properties to be defined: the store used for data and the itemTpl responsible with displaying the data. We want our list to display the title and date for each of our news items, so we put in curly braces the name of the properties we’ve defined in our News model.

Let’s style the list items a little by opening res/css/style.css and adding:

.x-list-item-body {
	font-size: 0.8em;
	color: #0b3e7b;
	font-weight: bold;
}
.x-list-item-body .date {
	color: #666;
	font-weight: normal;
}

Here’s how the news list should look:

MvcTouch part 4 news list

For more info on List component you can watch the Intro to the List Component screencast. To find what else you can do in the itemTpl property you can watch XTemplates; part I and part II screencasts.

Creating a details screen

All we have to do now is to show a details screen when a list item is tapped.

First let’s create the view by adding a file named NewsDetailsView.js in views/news/ with the following content:

App.views.NewsDetails = Ext.extend(Ext.Panel, {
    scroll: 'vertical',
    styleHtmlContent: true,
    style: 'background: #d8efed',

    initComponent: function()
    {
        if (this.newsItem)
        {
        	this.html = '';
            this.html += '<h3>'+ this.newsItem.get('title') +'</h3>';
            this.html += '<p>'+ this.newsItem.get('date') +'</p>';
            this.html += '<p>'+ this.newsItem.get('content') +'</p>';
        }

        App.views.NewsDetails.superclass.initComponent.apply(this, arguments);
    }
});
Ext.reg('NewsDetails', App.views.NewsDetails);

With the details view created, we now need to catch the event triggered by the list when an item is selected, so modify the news controller index action like this:

...
this.indexView = this.render({
    xtype: 'NewsIndex',
    listeners: {
        itemtap: function(view, index){
            this.selectedNewsItem = view.store.getAt(index);
            Ext.redirect('News/details');
        },
        scope: this
    }
});
...

As you can see on itemtap event we pass a function that has two parameters: the first one will be the instance of the list component and the second will be the index of the selected item. Using the store from the list component we can retrieve the record associated with the item selected by using the getAt function of the store by passing the index as the parameter. The returned record it will be a NewsItem model instance and we’ll store it as a property in the News controller in order to be accessible from the details action we’ll create next.

News controller details action:

details: function(options)
{
    if ( ! this.selectedNewsItem)
    {
        Ext.redirect('News/index');
        return;
    }

    if ( ! this.detailsView)
    {
        this.detailsView = this.render({
            xtype: 'NewsDetails',
            newsItem: this.selectedNewsItem,
            listeners: {
                deactivate: function(view){
                    view.destroy();
                    delete this.detailsView;
                },
                scope: this
            }
        });
    }

    var backBtn = this.application.viewport.query('#backBtn')[0];
    backBtn.show();

    backBtn.setHandler(function()
	{
    	Ext.dispatch({
    	    controller: 'News',
    	    action: 'index',
    	    historyUrl: 'News/index',
    	    //
    	    animation: {
    	        type: 'slide',
    	        reverse: true,
    	    },
    	});
	});

    this.application.viewport.setActiveItem(this.detailsView, options.animation);
}

First, if there is no selected news item the app will redirect to news index action. Next we pass the news item to the details view in the render function. Also we use the deactivate event to destroy the details view when it’s not needed.

For more info on Listeners you can watch the Intro to Listeners screencast.

If you select a news item from the list you should see a details screen like this:

MvcTouch part 4 news details

This is the end of part 4 and of the series!

You can download the final version of the project from here.

If you have questions, suggestions or improvements don’t hesitate to add a comment and let me know about them.

If you liked this post
you can buy me a beer

70 Responses to Creating a Sencha Touch MVC application from scratch, part 4

  1. Is it possible to add some more gestures, like swipe to right is going back to the details and a swipe to the left is going the next message? If so, how can this be accomplished?

    Thanks for your tutorials!!! 😀

    • To accomplish the behavior you’ve described you need to alter the creation of the details view like this:

      this.detailsView = this.render({
          xtype: 'NewsDetails',
          newsItem: this.selectedNewsItem,
          listeners: {
              deactivate: function(view){
                  view.destroy();
                  delete this.detailsView;
              },
              el: {
              	swipe: this.onDetailsSwipe,
              	scope: this
              },
              scope: this
          }
      });
      

      and to add a new method to the controller:

      onDetailsSwipe: function(event)
      {
      	if (event.direction == 'right') // back to news items list
      	{
      		Ext.dispatch({
          	    controller: 'News',
          	    action: 'index',
          	    historyUrl: 'News/index',
          	    animation: {
          	        type: 'slide',
          	        reverse: true,
          	    },
          	});
      	}
      	else // show next item
      	{
      		var store = Ext.StoreMgr.get('NewsItems');
      		
      		// find the next item
      		var index = store.indexOf(this.selectedNewsItem);
      		this.selectedNewsItem = store.getAt(index + 1);
      		
      		if (this.selectedNewsItem)
      		{
      			// get detailsView configuration object
      			if ( ! this.detailsViewConfig)
      			{
      				this.detailsViewConfig = this.detailsView.initialConfig;
      			}
      			
      			// update the view with the new item
      			this.detailsViewConfig.newsItem = this.selectedNewsItem;
      			
      			// create a new details view
      			var nextDetailsView = this.render(this.detailsViewConfig);
      			
      			// show the new details view
      			this.application.viewport.setActiveItem(nextDetailsView);
      		}
      	}
      }
      
  2. I’m struggling with getting a nestedlist working. I was wondering if you were planning on rereleasing a version of this tutorial in Sencha Touch 2?

  3. Thanks for the Demo. Nice Work

    I just copy pasted the code and published it on a local tomcat apache server. It runs fine on Google chrome, but when I run it in my iPad or iPhone the initial load time is very slow. Once it loads the subsequent refresh/reloads are instant.

    Anyways idea why this is happening?

  4. Himanshu Rathore

    Hey CAM it’s a great post.After gone through to ur tutorials i have decided to create an app in sencha touch.In one module i need to call a ASP.NET web service in sencha touch but i have failed becoz i haven’t found any good tutorials on net.So i request you to post some tutorials about calling ASP.NET web service in sencha touch.Thanx in advance.

    • The technology you use on your server has nothing to do with the Sencha Touch application. With Sencha Touch you can make ajax/jsonp calls to a server no matter if the script that is ran is written in php, asp, asp.net, java, perl etc. It is not the point of this series of tutorials to show how you can use post/get and render some output in asp.net (since basically that’s what you are asking)

      • Himanshu Rathore

        hey I have posted my quetion here :-http://stackoverflow.com/questions/9583772/not-getting-success-in-calling-asp-net-web-service-from-sencha-touch
        Please give me the possible solution of the question.

  5. this is really a very very excellent tutorial i must say, i followed it and did some changings with your code, i loaded product categories from db using php, now wen i tap on any of the category it redirected me to the items list page, but didnt filters the items with reference to selected category, please guide. thanks in advance

  6. Excelente tutorial !

    Muito obrigado.

  7. Hi Cam,

    I followed your example . Its great help. I in details view i have video and some button using html . I want add some listeners for them . Can you suggest me where and how i can add ?

    Regards,
    swapnil

  8. Hi Cam,

    Your example of splitsview is great helpfull. But i want to use sencha touch 2.0 . similar code gives error . Do you have anything similar for 2.0. Can you provide me link?

    Thanks ,
    swapnil

  9. Love these tutorials!

    Quick question, how would you combine your TabBar with the above?

    In your TabBar tutorial, you have Home and About. Could you have it where on the Home it has the News Button, and perhaps another button that wasn’t an icon in the bottom tab bar?

    Excellent work!

  10. json is not working

Add a Comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Also, if you want to display source code you can enclose it between [html] and [/html], [js] and [/js], [php] and [/php] etc