+44 (0) 7918 168 992

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. Excellent tutorial. I’ve learned a few principles when using MVC.

    This will be handy for me when I start my personal project using Sencha Touch.

    Thank you

  2. Just a quick question : Why would you destroy and delete details view?
    I do use destroy() but never seen delete afterward. Thanks!

    • If you do something like

      if ( ! this.detailsView)
      {
          this.detailsView = this.render({
              ...
          });
      }
      

      and on deactivate you destroy the component, the next time the details action is called the view will not be re-rendered because it will never enter that if statement.

      The destroy() method only deletes the component markup data from the DOM, so this.detailsView will still point to the instance of it. So, we must either assign a value of null to that variable or delete it. I prefer to delete the variable.

  3. Does the MVC architecture support a splitview type of setup? I’m wondering how the cards would react to a left column nestedList when a list item is tapped. Any insight on this?

    Thanks CAM, great set of tutorials!

    • Hello, John.

      I’ve modified the project from this article to show the news using a splitview like this:
      MvcTouch part 4 splitview
      You can download the modified project from here.

      Files modified: NewsIndexView.js, NewsDetailsView.js, NewsController.js (look at itemtap event handler from index action) and style.css.

  4. i have a problem, im trying to read a json file, i tried your code and it doesnt work for me, when i press the news button it doesnt show anything only the loading symbol and it doesnt finish.

    what do you think is the problem?

  5. There is a bug with profiles when using MVC, any thoughts on a work around? There is a forum post here: Ext.regApplication is not compatible with application profiles

    This doesn’t seem to work.. though maybe because there isn’t a complete example?

  6. I want u to show about Sencha Touch Version 2 , and post on this wab

  7. These guides are great, I know hardly any programming and no JS, but they are clear and easy to understand! You definitely got a knack for explaining things well.

  8. Hey CAM
    As said before, excellent job. I am creating large apps in this way.
    I am having a problem and I hope someone in here or CAM can help me with a solution.
    When pressing a button, itemTap ect. there is a delay from key-pres to actual setActiveItem(”) is executed/done. What can I do? Now you don’t know if it has registered the keypres and you feel like pressing the list item again because you don’t know if it was registered. I have tried to put setLoading on ect. but nothing works. Any advice?

  9. Hi, David.

    How many items are there in the list?
    Maybe you are doing something before setActiveItem that freezes the app for a moment.
    Without some code to see or test I can’t tell you something useful.

  10. Hi CAM,

    The problem and a solution is here:
    http://appointsolutions.com/2011/08/sencha-touch-loadmask-delayed-rendering/

    We are talking ½-1 second but it just feels slow when nothing happens instant. The fix above works. Do you know another solution?

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