Showing posts with label Sencha Touch. Show all posts
Showing posts with label Sencha Touch. Show all posts


Today I will tell you how to get reliable geolocation data on Cordova or Phonegap. It took me a lot of time to figure all this out, so I hope that I can save you some precious time with my article.

Note: I tested on Cordova 3.4.x and Android/WindowsPhone.

Before we start, make sure that you have not installed the Cordova or Phonegap geolocation plugin! In case you already have, remove it with the following command "cordova plugin remove org.apache.cordova.geolocation". We do not need this plugin since the native HTML5 support is much better! Further information can be found here. I don't know why this plugin is still available in the official documentation... But don't worry if you come from Cordova or Phonegap, you don't have to change a lot in your existing code (maybe you have to eliminate the frequency attribute).

Please pay attention that, also when you are not using the geolocation plugin, you have to set the following privileges in your:

AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
WPAppManifest.xml

<Capabilities>
               <Capability Name="ID_CAP_LOCATION" />
</Capabilities>
The code for the implementation itself is relative trivial. I would suggest you to implement it after the following action plan:

  • Before you do anything, check if geolocation is available (navigator.geolocation)
  • Try to get the current position with high accuracy, if the request timed out or an error occur > fallback to lower accuracy.
Important parameter:
  • enableHighAccuracy: true/false for high or low accuracy
  • maximumAge: Accept a cached position whose age is no greater than the specified time in milliseconds. (Number)
  • timeout: Maximum time of lenght in ms to get the position.
  • frequency: Stop using this attribute. It is not W3C compliant. Use maximumAge instead!
Suggested values:
  • enableHighAccuracy: true, maximumAge:3000, timeout: 5000
  • enableHighAccuracy: false, maximumAge:3000, timeout: 30000

Tips:
  • If you want to update your geolocation data continuously, use watchPosition(...) instead of getCurrentPosition(...). Also use the pause/resume functions of Cordova/Phonegap to start/stop the watch while the application is or return from background. The users battery will thank you.
  • Keep in mind that the logic behind getCurrentPosition(...) and watchPosition(...) is differently on different devices. So test your implementation as much as you can!


Please let me know if this article helped you to improve your geolocation results. If you tested successfully with iOS drop a comment (ideal with required privileges) as well. Thanks!

Most of the lists in Sencha Touch are connected to a store. When the store only contains a small amount of records, performance is not a problem. However, when the store is filled with a big amount of records, it is very important that the data is added in an optimum manner.

Let's have a look at the following code:
copyObjects : function(objects) {
   var taskModel = null, 
       taskStore = Ext.getStore('Tasks');

   taskStore.removeAll(true);

   Ext.Array.each(objects, function (data) {
      taskModel = Ext.create('MyApp.model.Task', data);
      taskModel.setDirty(true);
      taskStore.add(taskModel);
   });
   taskStore.sync();
}
In the above example, 100 objects are added. Tested on a Samsung Galaxy II, the execution takes 12 to 14 seconds. It simply takes too long!

After further testing, I found out that the add function takes so much time (http://docs.sencha.com/touch/2.3.1/source/Store.html # Ext-data-store-insert method). Therefore, the solution is to call this function as less as possible. This can be done with a temporary array:
copyObjects : function(objects) {
   var taskModel = null, 
       taskStore = Ext.getStore('Tasks'),
       tmp = new Array();

    taskStore.removeAll(true);

    Ext.Array.each(objects, function (data) {
       taskModel = Ext.create('MyApp.model.Task', data);
       taskModel.setDirty(true);
       tmp.push(taskModel)
    });
    taskStore.add(tmp);
    taskStore.sync();
}
The execution time takes only one second now.

Advice: Pay attention that your list is not too long, because the scrolling performance will go down as well.


I think everyone who deploy a first app on Windows Phone is facing the same problem: The app is running fine, but where the heck are my icons?

Apparently there is an issue present in Windows Phone 8 that prevents custom font-faces from working when HTML and CSS are hosted locally.

So we came up with the first solution: Hosting everything remote. But really, this is not a solution, right?

After spending some more time on google, I found another solution: Including the font-file instead of the base 64 encoded font.

Sample Code:
@font-face {
 font-family: 'Pictos';
 src:url('fonts/pictos-web.woff') format('woff');
 font-weight: normal;
 font-style: normal;
}
However, this code never worked for me. Some user reported that it works, but the rest said that it doesn't work for them too or only for some and not all of their font files.

Finally I came up with another idea: When I cannot rely on the CSS font-face, then I'll go back to the roots and display pictures instead. Of course this costs more effort and is not as elegant as using icon fonts, but so far this seems to be the only safe solution to get it done.

Before we start, let me tell you that we don't have to modify any of the Java Script Code and it will not affect other platforms like Android or iOS.

If you are already working with Themes (what I would suggest you) then you can just place the new CSS code to your WP.scss

To reduce the CSS markup, I created a small mixin. In this mixin we set a new background image with height and width, also we replace the characters in content with an empty string:

@mixin wpIcon($name,$dim) {
  $url:"../images/wp/#{$name}.png";
  background: transparent url($url) 0 0 no-repeat;
  content: '';
  height: $dim;
  width: $dim;
  display: inline-block;
}

The sample code above requires that your images are located in "/resources/images/wp".

Replacing images is very straight forward, lets take a look at another sample which shows how to use this mixin:
/* Replace the checkbox checked icon */
.x-input-checkbox:checked ~ .x-field-mask:after {
  @include wpIcon(checkmark, 20px);
}

/* Replace the back button icon and add a second rule for back button pressed */
.x-button-back:before {
  @include wpIcon(arrow-left, 32px);
}

.x-button-back.x-button-pressing:before {
  @include wpIcon(arrow-left-pressed, 32px);
}
As you can see we just pass the image name (without the file extension) + a size to the mixin.

If you don't use the WP.scss yet you can add ".x-windowsphone" as an additional class to your CSS rule. This makes sure that the rule will only apply on Windows Phone.

I hope this trick help you to get your icons back on Windows Phone. Please let me know when you have even a better idea/solution for this problem.


In the early years of the Internet, it was possible to breach users security by using of JavaScript to exchange information from one website to another that has less reputation.

Therefore, all modern browsers implement the same origin policy that prevents attacks like cross-site scripting.

However, sometimes cross-origin HTTP request is a must-have requirement for a web application. This article will discuss about methods of how to deal with cross-origin HTTP requests. Lets start with some background information.

Origin policy

The algorithm used to calculate the "origin" of a URI (Uniform Resource Identifier) is specified in RFC 6454.

There are two different cases:
  1. Absolute URIs, the origin is the triple {protocol, host, port}
  2. If the URI does not use a hierarchical element as a naming authority (RFC 3986) or if the URI is not an absolute URI, then a globally unique identifier is used.
Two resources are considered to be of the same origin if and only if all these values are exactly the same.

The table below illustrates a check against the URL "http://www.example.com/pages/index.html":
URL to compare Result Why?
http://www.example.com/pages/index2.html ok Same host and protocol
http://www.example.com/pages2/index.html ok Same host and protocol
httpː//username:password@http://www.example.com/pages/index.html ok Same host and protocol
http://www.example.com:8080/pages2/index.html fail Same host and protocol, but different port
https://www.example.com/pages/index.html fail Different protocol
http://sub.example.com/pages/index.html fail Different host
http://example.com/pages/index.html fail Different host
http://www.example.com:80/pages/index.html - (Different port) Depends on the browser implementation


If the policy cannot be applied, the web browser will respond with an exception message, such as the following:

XMLHttpRequest cannot load ...
Cross origin requests are only supported for HTTP.
Uncaught NetworkError: A network error occurred.

Relaxing the same origin policy

Here are some techniques to relax with origin policy:
  • JSONP. If the requirement was to get only the data from a different domain, then a JSONP request is the best choice. JSONP includes external data via the <script> tag.
  • Cross origin resource sharing. This extends HTTP with a new origin request header and a new Access-Control-Allow-Origin response header. This article describes how to enable CORS.
  • Disable web security (for development mode only). If an application is under development, the web security can temporarily disabled for the web browser. While the web browser is in an unsecured mode, it is highly recommended not to surf on public Internet pages (since the browser is vulnerable for all cross site scripting attacks). See "Disable web security for a web browser".
  • Reverse Proxy. A reverse proxy (or gateway), by contrast, appears to the client just like an ordinary web server. No special configuration on the client is necessary. The client makes ordinary requests for content in the name-space of the reverse proxy. The reverse proxy then decides where to send those requests, and returns the content as if it was itself the origin. See "Setup a reverse proxy".
  • Whitelist (PhoneGap). If a web application is deployed to a mobile device with PhoneGap the domain can whitelisted (Whitelist Guide).

Disable web security for a web browser

For Google Chrome, the following command must executed in Terminal (browser must be closed):

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-web-security

Setup a reverse proxy

Nowadays there are many http servers on the market, however this article focuses on how to configure a reverse proxy with XAMPP.

Install XAMPP

XAMPP is a free and open source cross-platform web server solution stack package, consisting mainly of the Apache HTTP Server, MySQL database, and interpreters for scripts written in the PHP and Perl programming languages.

You can download XAMPP here http://www.apachefriends.org/en/xampp.html.

Configure a virtual host

A virtual host gives you the possibility to run several name-based web applications on a single IP address.

Configuring the virtual host on your web server does not automatically cause DNS entries to be created for those host names. You can put entries in your hosts file for local testing.

Make a local host file entry

  1. Open your Terminal.
  2. Type: "sudo vi /private/etc/hosts" to open the host file.
  3. Add the following entry "127.0.0.1 local.app.com" to the end of this file. You can modify this domain name to your needs.
  4. Save the file and close it.

Configure XAMPP

  1. Open your Terminal.
  2. Open the XAMPP virtual host file. "sudo vi /Applications/XAMPP/etc/extra/httpd-vhosts.conf"
  3. Add the following virtual host entry to the end of this file:
<VirtualHost *:80>
  DocumentRoot "/Volumes/workspace/myHtml5App"
  ServerName local.app.com
  ProxyPass       /service.php       http://yourExternalHost.com/communication/service.php
</VirtualHost>

Short explanation:
  • "*:80" Listen for virtual host requests on all IP addresses.
  • "DocumentRoot" Destination of the web application on the filesystem.
  • "local.app.com" Server name, must be the same name as in the host file above.
  • "ProxyPass" Proxy path holds the service address.
Before you restart the server, make a quick check to the httpd.conf file. ("sudo vi /Applications/XAMPP/etc/httpd.conf").

Make sure that the following entries are not commented with a "#"
  • "Include /Applications/XAMPP/etc/extra/httpd-vhosts.conf"
  • LoadModule proxy_module modules/mod_proxy.so
  • LoadModule proxy_connect_module modules/mod_proxy_connect.so
If all is fine, restart your server.

If you call "local.app.com" in your browser, the web application should open. But you will still receive a cross origin policy exception, because your web application still sends the requests to "http://yourExternalHost.com/communication/service.php".

To fix this, replace the URL "http://yourExternalHost.com/communication/service.php" with "local.app.com/service.php" in your web application.


After I came back from my last vacation, the first thing I did was updating my system to Mavericks. Of course, I read some recommendations before if it is worse to update or not, but after some researches I thought nothing can go wrong :)

The OS X update itself worked for me like a charm without having any problems, but there was one thing I mentioned first: Java is no more included in OS X 10.9 Mavericks. Ok this was easy to fix. The real problem started after I wanted to build my Sencha Touch application via Sencha CMD.

When I started the Sencha CMD build I received a message, that not the right Ruby version is installed on my system.
[ERR] Detected ruby version 2.0.0 was not less than 2.0. Please install ruby 1.8 or 1.9
After some researches on the web, I found the following information:

  • Ext JS themes use Sass variables whose value are set to "null !default".
  • Sass changed the behavior of such things and broke those themes.
  • Sencha Cmd embeds a version of Sass that is known compatible with Ext JS themes.
  • Ruby 2 changed some API and broke that version of Sass.
So the only solution for my problem was going back to Ruby 1.9 to make my Sencha CMD build working again.

There are a lot of ways to downgrade Ruby, but a very straight forward and easy way by using RVM is described in the following article: http://moduscreate.com/sencha-cmd-not-working-in-os-x-10-9-mavericks/


Chrome has a new flex layout support since version 29.0.1547.57, this cause a broken layout in Sencha Touch 2.2.1.

Fix this issue by changing the rule order of the st-box mixin.

Open resources/themes/stylesheets/sencha-touch/base/mixins/_Class.scss in a text editor and replace the mixin st-box with the following:

@mixin st-box($important: no) {
    @if $important == important {
        display: flex !important;
        display: -webkit-box !important;
        display: -ms-flexbox !important;
    } @else {
        display: flex;
        display: -webkit-box;
        display: -ms-flexbox;
    }
}
After re-compiling your css, your application layout should look as nice as in prior Chrome versions.
During the last view days I was evaluating the Sencha Architect (Version 2.2.2). Most of the things that I wanted to implement were not a problem. But then I wanted to add a custom property in the controller section.
config: {
        /**
         * @private
         */
        viewCache: []
}
At first I thought no problem, that is easy. But in the end it has taken some time to find this out. So here comes the trick:

Go to the "Project Inspector". Type the name of your custom property in the search field of the config pane then click the "add" button or hit your enter key. After that you can change the type. See below:



Sencha Touch includes some notable features. The function Ext.Function.createThrottled is one of them.

This function prevents multiple function execution. The interval on which the passed function is executed can defined additionally.

Ok, let's take a look into the code:
// The function to execute at a regular time interval.
var fn = function () {

console.log('fired');
};

// The intervall in milliseconds on which 
// the passed function is executed.
var intervall = 5000; // 5 seconds

var myFunc = Ext.Function.createThrottled(fn, intervall, this);

// Excecuted immediately
myFunc();

// No matter how often myFunc() is called,
// it is only executed once and after 5 seconds
myFunc();
myFunc();
myFunc();
myFunc();
myFunc();
myFunc();
Tip: The function can be assigned to a class variable that is initialized via a constructor or init().
Meanwhile, there are many tools on the market for remote debugging, but remote debugging is still damn tricky.

In this post I'd like to introduce http://jsconsole.com in combination with a Sencha Touch application to you.
jsconsole is a simple JavaScript command line tool. However, it also provides the ability to bridge across to other browser windows to remotely control and debug that window - be it in another browser or another device altogether.
First we need to create a new ID for the device that we want to debug. Jump to http://jsconsole.com and enter the following command in the console:
:listen
After the command ":listen" is entered, the following output appear:
As can be seen in the output, a new ID is generated.

Hint: It is also possible to listen to a predefined device. Just type: ":listen <ID>".

The next thing we have to do is to include the script in our application. The script can be integrated as follows in the "app.json":
  "js": [
    {
      "path": "http://jsconsole.com/remote.js?AE61E3FB-7B1B-4367-8DEC-AD476FC9CA5F",
      "update": "full",
      "remote": true
    },
Now any calls to console.log from your application will display the result in the jsconsole session that is listening to your ID.

It is also possible to inject code into the remote application. As a simple example, write "alert ('test');" in jconsole. On the remote application, a message box with the text "test" should appear. Of course it can also be injected much more complex code.
For this reason, this script should never be used in a production environment!

More information about jconsole is available here.


I would like to take this opportunity to explain a few pitfalls that arise when in development with Sencha. This article is designed to help develop Sencha applications faster and more robust.

If you should find that something important is missing or something is wrong, do not hesitate to contact me.

Loading Sencha Framework and external Resources

It is recommended that the Sencha framework is loaded via the Microloader.

The "index.html" should be kept as lightweight as possible to avoid negative side effects. It seems Sencha has problems, for example, when trying to place child elements within the body region.

Below is an example of linking against the Sencha Touch framework:
<!DOCTYPE HTML>
<html manifest="" lang="en-US">
<head>
    <meta charset="UTF-8">
    <title>Your Application</title>
    <script id="microloader" type="text/javascript" src="touch/microloader/development.js"></script>
</head>
<body></body>
</html>
If additional JavaScript files required, these should not be included in the "index.html". Additional JavaScript files and CSS should always defined in the file "app.json".

The defintion of the files in the "app.json ' has the following advantages:
  • Included files are automatically compressed during the Sencha Build process. 
  • Included files can be loaded depending on the target platform. 
  • The application loads faster. 
  • index.html is lightweight.

Styling your Application

When it comes to styling your application, Sencha has a few ways to do this directly in JavaScript. However, this should be avoided. All style information should be defined via CSS or better SASS.
This results in the following advantages:
  • The actual source code is lightweight. 
  • All style information are defined centrally. 
  • The application can be easily edit at the same time by several developers. 
  • The design can be flexibly adapted at any time.

The app.js File

All changes to this file should be as minimal as possible. The reason for this, as soon as a Sencha update is performed, this file must be manually merged with the update.

Using Ext.getCmp()

The use of the function Ext.getCmp() should be largely avoided. The use of this function makes the source code hard to read and maintainable. By using the MVC principle, the function should no longer be needed.
See also MVC in depth Part 1 and MVC in depth Part 2.

In short, if Ext.getCmp() is used, the developer has missed the object-oriented approach.

In many applications, this function is still used to prototype faster or because the programmer does not know better.
When using Ext.getCmp() is essential to make sure that the object exists. I.e. the object must not be 'undefined' when its function is called. Otherwise, the interpreter throws an exception.

Using Ext.Viewport.removeAll() to destroy components

In the life cycle of an application it often happens that components are no longer needed. A good example to log out in an application. It is tempting to destroy all components on the Viewport with the Ext.Viewport.removeAll (http://docs.sencha.com/touch/2.2.1/#!/api/Ext.Container-method-removeAll) command:
Ext.Viewport.removeAll(true, true);
At first glance, all components were destroyed which were located on the Viewport. But what happens if the user now wants to re-login? Furthermore, we assume that the user enters his password incorrectly, and we show via Ext.Msg an error message.
Unfortunately, the following error message is displayed instead Ext.Msg:
Uncaught TypeError: Cannot read property 'dom' of null
Ext.Msg is a singleton instance of Ext.MessageBox. When you do the removeAll(true, true) the second argument is to destroy everything, inner items, docked items and floating items. Ext.Msg is a floating item so you have destroyed Ext.Msg, but you are then trying to use it. Now, if the component is destroyed it ends with the error message above.
It is recommended to destroy all the components separately. Not with "Ext.Viewport.remove" but directly through "myObj.destroy();"

Naming Model, Store and View

In the naming of models, views, and stores should pay attention to the following:
Basically, the name always begins with a capital letter, all the following words also with a capital letter.
  • Model, in the singular. Example: "TrainStation.js" 
  • Store in the plural. Example: "TrainStations.js" 
  • View, in the singular. Example: "TrainStation.js" 
Following this convention, the structure of the application is easier to read and quicker to learn.

JavaScript === versus == (Comparison Operators)

The identity "===" operator behaves identically to the equality "==" operator except no type conversion is done, and the types must be the same to be considered equal.

If values ​​are compared with each other it is recommended to use "===" instead of "==". This makes the program less error prone.

This is also the case for "!==" and "!=".

See also http://www.c-point.com/javascript_tutorial/jsgrpComparison.htm

Stop over nesting the View

When creating new views, make sure that they are as lightweight as possible. I.e. you should not go deeper than it is absolutely necessary in the structure. The use of unnecessary panels is a prime example of this. Is a view nested too deeply, it will have a negative impact on the performance of the application.

Is a view defined with "Ext.View", the view should not contain any action listener. These are defined in the relevant controller. This has the advantage that the view is more legible.

In short, in the view there is no business logic! All business logic should always be to find in the respective controller.

Code Completion

If the application is developed in Eclipse there are two ways to obtain a code completion. The first way is to use Spket. How this works can be found here. The second alternative is to purchase Sencha Complete. This version includes the necessary Eclipse plugins.

JSLINT for better source code

For the development of JavaScript applications, it is recommended to use JSLint. Who JSLint does not know yet, thus it is possible to validate your code against best practices. How to configure Eclipse with JSLint is described here.

Icon fonts instead of the classic icons

One element of themes in Sencha Touch 2.2 is the new use of icons as fonts. This is an awesome feature, because this offers the following new features:
  • size can be easily changed. 
  • color can be easily changed. 
  • shadow can be easily added to their shape. 
  • transparency nearly everywhere, unlike transparent png's in ie6. 
  • smaller in file size 
  • infinitely scaleable (because vector)
The goal of using icon fonts is to replace the need to render icons on a web page using images.

Click here to continue...

Using ComponentQueries instead of Id Config

Avoid using the id config, let ComponentQuery resolve the component using xtype with a property.

For those who are not familiar with ComponentQueries yet, they are used to retrieve pointers to one or many components in the application using a syntax similar to that of CSS selectors.

Let‘s compare the following cases. With Id Config, we define the following Sencha controller:
Ext.define('MyApp.controller.Main', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            myButton: '#buttonId'
        },
        control: {
            myButton: {
                tap: 'onButtonTap',
                change: 'onButtonChange'
            }
        }
    },
});

As seen in the above example, we refer to the button with "#buttonId". The code would work for now. But what happens if we destroy the view with the button on it and then re-create the view?

The result is, the "tap" handler fires, but not the "change" listener. The controller reference do not point to the button anymore. The reason being is, the button has been referenced via the config id. As you can clearly see Id Config is lack of flexibility.

Here is the same case, but using the ComponentQuery:

Ext.define('MyApp.controller.Main', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            myButton: 'button[id=buttonId]'
        },
        control: {
            myButton: {
                tap: 'onButtonTap',
                change: 'onButtonChange'
            }
        }
    },
});
There is no difference between quoted and unquoted references. myButton and also "myButton" are valid references. 

More about ComponentQueries

ComponentQueries can be built with: 
  • The XTYPE-property
  • Attributes in brackets, i.E. 'button[action=submitForm]' 
  • Functions which return true/false values in curly braces '{isValid()}'
  • The itemId property '#itemId'
  • The 'not' operator. Used to retrieve all components that are not the pointed component. I.E. 'not textfields'
  • Like in css '>' can used for parent and child relationships ('panel > button'). 
  • Multiple queries can be separated by using ','. I.E. 'button, textfield'

Testing ComponentQueries

ComponentQueries are mostly defined in controllers (ref section), but it is also possible to use the singleton object Ext.ComponentQuery (http://docs.sencha.com/touch/2.2.1/#!/api/Ext.ComponentQuery). To run and test a ComponentQuery,  there is a handy option in the JavaScript console. I.E Ext.ComponentQuery.query('panel > button')

Using itemId instead of id

I recommend you not to use the "id" attribute for the identification of components. The problem is that the "id" must be unique throughout the entire application. Replace "id" with "itemId" will avoid this conflict. The itemId property requires uniqueness of value only among child components of a container.

Caution: If the itemId used in a ComponentQuery, the itemId must either pre-qualified via a parent item and/or you could put its xtype#myItemId.

Short example. We  define a button with the itemId="navButton" and the parent container of our button has the xtype="navigation". So our config could look like this:
Ext.define('MyApp.controller.Main', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            myButton: 'button#navButton'
        },
        control: {
            myButton: {
                tap: ...
            }
        }
    },
});

While itemIds are not unique throughout the entire application, it is a good advice to put the xtype into the query too. So instead of 'button#navButton' we use the following query: 'xtype button#navButton' to gain more precision:
Ext.define('MyApp.controller.Main', {
    extend: 'Ext.app.Controller',

    config: {
        refs: {
            myButton: 'navigation button#navButton'
        },
        control: {
            myButton: {
                tap: ...
            }
        }
    },
});

Using GLOBAL Variables

It is generally advised not to use global variables. First problem, there is no namespace for these variables. Second problem, the debugging of these variables often proves to be very difficult.
messageText = 'My message text.';
timeout = 5000;
In the above example, the variable "messageText" and "timeout" was defined as global. A better solution is to define these variables in a separate class.
Ext.define('MyApp.util.Config', {
    singleton : true,
    alternateClassName : ['Config'],

    config : {
        app : {
            messageText = 'My message text.'
            //...
        },
        services : {
            timeout = 5000;
            //....
        }
    },
    constructor: function () {
        return this.config;
    }
});
The new class "Config" is included in the "app.js" file via require:
Ext.application({
    name : 'MyApp',

    requires: [
        'MyApp.util.Config'
        //...
    ],
    //...
});
Access to the variables is done with:
Config.app.messageText
Config.services.timeout
Alternatively setter and getter functions can be automatically generated by Sencha. The Config class looks like this:
Ext.define('MyApp.util.Config', {
    singleton : true,
    alternateClassName : ['Config'],
    config: {
        messageText = 'My message text.',
        timeout = 5000
    },

    constructor: function(config) {
        this.initConfig(config);
    }
});
Access to the variables is done with:
Config.getTimeout();
Config.getMessageText();


One element of themes in Sencha Touch 2.2 is the new use of icons as fonts. This is an awesome feature, because this offers the following new features:
  • size can be easily changed. 
  • color can be easily changed. 
  • shadow can be easily added to their shape. 
  • transparency nearly everywhere, unlike transparent png's in ie6. 
  • smaller in file size 
  • infinitely scaleable (because vector) 
The goal of using icon fonts is to replace the need to render icons on a web page using images.

Requirements

To use this new feature it is mandatory to setup your project with SASS. If your project not yet including SASS, take a look at this article "Theming Sencha Touch with SASS".

Out-of-the-box icons

The lightweight Sencha Touch 2.2 default theme already includes some basic icons. It is shipped with 27 icons in total.

The default icon set includes:
action, add, arrow_down, arrow_left, arrow_right, arrow_up, bookmarks, compose, delete, download, favorites, home, info, locate, maps, more, organize, refresh, reply, search, settings, star, team, time, trash and user.
Use the default icons above by typing:
{  xtype: 'button',  iconCls: 'user',  title: 'User'  }

Extend the Out-of-the-box icons

Sencha Touch 2.2 is now using the http://www.pictos.cc/font/ library. When you checkout this website, you'll find out that they have more to offer in terms of icons.

At the first glance, the icon collections on the website might be a little bit confusing. You might ask yourself how does the mapping works between the "iconCls" and the pictos.

Well, when you take a look inside the framework of Sencha Touch 2.2, you will find the following mapping in "Sencha Touch SDK/resources/themes/stylesheets/sencha-touch/base/mixins/_Class.scss":
@function icon-character-for-name($name) {
    // http://pictos.cc/font/

    // Row 1
    @if ($name == "anchor") { @return "a"; }
    @else if ($name == "box") { @return "b"; }
    @else if ($name == "upload") { @return "c"; }
    @else if ($name == "forbidden") { @return "d"; }
    @else if ($name == "lightning") { @return "e"; }
    @else if ($name == "rss") { @return "f"; }
    @else if ($name == "team") { @return "g"; }
    @else if ($name == "help") { @return "h"; }
    @else if ($name == "info") { @return "i"; }
    @else if ($name == "attachment") { @return "j"; }
    @else if ($name == "heart") { @return "k"; }
    @else if ($name == "list") { @return "l"; }
    @else if ($name == "music") { @return "m"; }
    @else if ($name == "table") { @return "n"; }
    @else if ($name == "folder") { @return "o"; }
    @else if ($name == "pencil") { @return "p"; }
    @else if ($name == "chat2") { @return "q"; }
    @else if ($name == "retweet") { @return "r"; }
    @else if ($name == "search") { @return "s"; }
    @else if ($name == "time") { @return "t"; }
    @else if ($name == "switch") { @return "u"; }
    @else if ($name == "camera") { @return "v"; }
    @else if ($name == "chat") { @return "w"; }
    @else if ($name == "settings2") { @return "x"; }
    @else if ($name == "settings") { @return "y"; }
    @else if ($name == "tags") { @return "z"; }

    // Row 2
    @else if ($name == "attachment2") { @return "A"; }
    @else if ($name == "bird") { @return "B"; }
    @else if ($name == "cloud") { @return "C"; }
    @else if ($name == "delete_black1") { @return "D"; }
    @else if ($name == "eye") { @return "E"; }
    @else if ($name == "file") { @return "F"; }
    @else if ($name == "browser") { @return "G"; }
    @else if ($name == "home") { @return "H"; }
    @else if ($name == "inbox") { @return "I"; }
    @else if ($name == "network") { @return "J"; }
    @else if ($name == "key") { @return "K"; }
    @else if ($name == "radio") { @return "L"; }
    @else if ($name == "mail") { @return "M"; }
    @else if ($name == "news") { @return "N"; }
    @else if ($name == "case") { @return "O"; }
    @else if ($name == "photos") { @return "P"; }
    @else if ($name == "power") { @return "Q"; }
    @else if ($name == "action") { @return "R"; }
    @else if ($name == "favorites") { @return "S"; }
    @else if ($name == "plane") { @return "T"; }
    @else if ($name == "user") { @return "U"; }
    @else if ($name == "video") { @return "V"; }
    @else if ($name == "compose") { @return "W"; }
    @else if ($name == "truck") { @return "X"; }
    @else if ($name == "chart2") { @return "Y"; }
    @else if ($name == "chart") { @return "Z"; }

    // Row 3
    @else if ($name == "expand") { @return "`"; }
    @else if ($name == "refresh") { @return "1"; }
    @else if ($name == "check") { @return "2"; }
    @else if ($name == "check2") { @return "3"; }
    @else if ($name == "play") { @return "4"; }
    @else if ($name == "pause") { @return "5"; }
    @else if ($name == "stop") { @return "6"; }
    @else if ($name == "forward") { @return "7"; }
    @else if ($name == "rewind") { @return "8"; }
    @else if ($name == "play2") { @return "9"; }
    @else if ($name == "refresh2") { @return "0"; }
    @else if ($name == "minus") { @return "-"; }
    @else if ($name == "battery") { @return "="; }
    @else if ($name == "left") { @return "["; }
    @else if ($name == "right") { @return "]"; }
    @else if ($name == "calendar") { @return "\005C"; }
    @else if ($name == "shuffle") { @return ";"; }
    @else if ($name == "wireless") { @return "'"; }
    @else if ($name == "speedometer") { @return ","; }
    @else if ($name == "more") { @return "."; }
    @else if ($name == "print") { @return "/"; }


    // Row 4
    @else if ($name == "download") { @return "~"; }
    @else if ($name == "warning_black") { @return "!"; }
    @else if ($name == "locate") { @return "@"; }
    @else if ($name == "trash") { @return "#"; }
    @else if ($name == "cart") { @return "$"; }
    @else if ($name == "bank") { @return "%"; }
    @else if ($name == "flag") { @return "^"; }
    @else if ($name == "add") { @return "&"; }
    @else if ($name == "delete") { @return "*"; }
    @else if ($name == "lock") { @return "("; }
    @else if ($name == "unlock") { @return ")"; }
    @else if ($name == "minus2") { @return "_"; }
    @else if ($name == "add2") { @return "+"; }
    @else if ($name == "up") { @return "{"; }
    @else if ($name == "down") { @return "}"; }
    @else if ($name == "screens") { @return "|"; }
    @else if ($name == "bell") { @return ":"; }
    @else if ($name == "quote") { @return "\""; }
    @else if ($name == "volume_mute") { @return "<"; }
    @else if ($name == "volume") { @return ">"; }
    @else if ($name == "help") { @return "?"; }

    // Backwards compat; icons that are not in the font
    @else if ($name == "arrow_left") { @return "["; }
    @else if ($name == "arrow_right") { @return "]"; }
    @else if ($name == "arrow_up") { @return "{"; }
    @else if ($name == "arrow_down") { @return "}"; }
    @else if ($name == "organize") { @return "I"; }
    @else if ($name == "bookmarks") { @return "I"; }
    @else if ($name == "loop2") { @return "r"; }
    @else if ($name == "star") { @return "S"; }
    @else if ($name == "maps") { @return "@"; }
    @else if ($name == "reply") { @return "R"; }

    @else {
        @return null;
    }
}
Ok, lets try this:
{  xtype: 'button',  iconCls: 'speedometer',  title: 'Speedometer'  }
But as you see in the result, the icon is still missing! This is because we did not included the icon in our "*.scss" file yet (because it is not in the range of the default icon set). To do this, add the following line to your "*.scss" file:
@include icon('speedometer');

Change the color or size of an icon

Changing the color of an icon is easier now than ever. All you need to do is adding the following line to your "*.scss" file:
.x-button-icon {
    color: #fff;
}
Now the color of your icon should change to white.

In case you want to change the size of the icon:
.x-button-icon {
    font-size: 50px;
}
Pretty simple, isn't it?

Add a icon to Ext.List

If you want to add a icon to Ext.List you need to define your own css class, because Ext.List do not have the iconCls config attribute.

In this example we add an user icon to Ext.List.

Open your "*.scss" file and add the following lines:
.userCls:before {
    font-family: "Pictos";
    content: "U";
    font-size: 1.5em;
}
Using the ":before" selector in CSS you can insert the user icon before the anchor text. Similarly, you can also use the :after selector to insert the icon after the text.

Ext.List item:
xtype : 'list',
store : 'your store',
itemTpl : new Ext.XTemplate(
 '<span class="userCls"></span>',
 '<span>{name}</span>',
 ...

Add more custom Icon-Fonts

If you need more icons, you can also attach icons from http://icomoon.io/app/ or checkout more icon collections.

The way to add custom Icon-Fonts is explained in this video: http://vimeo.com/66191690

Conclusion

Well, I hope this article helps. If you have any question, please contact me. In the mean time - let's keep developing apps guys.
Today at work I faced an interesting issue, I spent so much time looking for an instruction of how to implement the Ext.Logger in Sencha Touch application. Unfortunately, there is no information about this in the official documentation. Therefore, just to save you some time I would like to explain some details that I found out during my research.

First of all, the described technique for implementing the Ext.Logger works for Debug-Mode only, which means, the created Log messages are not visible when you use one of the following build-modes:
  • testing 
  • production 
  • native 
  • package 
The initial Logger setup is done, by putting the following lines to your app.js file:
    //<debug>
    logger: {
        enabled: true,
        xclass: 'Ext.log.Logger',
        minPriority: 'verbose',
        writers: {
            console: {
                xclass: 'Ext.log.writer.Console',
                throwOnErrors: true,
                formatter: {
                    xclass: 'Ext.log.formatter.Default'
                }
            }
        }
    },
    //</debug>

Pay attention that you put these lines between the //<debug> comment tags. Anything between //<debug> and //</debug> will be removed after you do a build with Sencha Cmd. If you are not putting your Logger setup between these lines, you won't be able to build your application with Sencha Cmd again.

For further information also checkout src/log/writter. There you can see how to Log in browsers document title or how to do a remote Log.

After the main configuration is done, the Log messages can be implemented like:
    //<debug>
    Ext.Logger.info('Hello World!');
    //</debug>
Take also a look at http://docs.sencha.com/touch/2.2.1/#!/api/Ext.Logger for a complete list of the Ext.Logger methods.

While Sencha Cmd is removing all code between //debug, your application should also run a little bit faster after building it. At least when you are using a huge amount of logging information.
Happy Logging...
The following code shows how-to pre select your list items in Sencha Touch:

var itemsToSelect = ["soccer", "baseball"];
var index = -1;
var myList = getMyList();

itemsToSelect.forEach(function(itemToSelect) {

   index = myList.getStore().find('fieldName', itemToSelect);
   myList.select(index,true,false); 
});
While in the process of implementing a JSONP proxy writter the following message will pop up when running the code:
Error: [ERROR][Ext.data.proxy.Server#create] JsonP proxies can only be used to read data.
There is nothing in the Sencha Touch documentation, that tells me that a proxy writer can not be used.

After looking at the framework code it was clear to me, that the source code had not been implemented.

With that, you really do need a JSONP writer, otherwise you have to implement the logic yourself or switch back to an AJAX proxy.

There is nothing in the release notes to Sencha Touch 2.2.0 beta 1 that leads me to believe, that any updates on the subject are forthcoming.
Maybe you received  the following error while building a Sencha Architect application:

Error: The package command has moved to 'sencha app package'

This error is thrown because Sencha Architect 2.1 only works with Sencha Cmd 3.0.0 version.

To fix this you have to download and refer one of the following Sencha Cmd 3.0.0 versions:

http://cdn.sencha.com/senchacmd/SenchaCmd-3.0.0.250-linux-x64.run.zip
http://cdn.sencha.com/senchacmd/SenchaCmd-3.0.0.250-linux.run.zip
http://cdn.sencha.com/senchacmd/SenchaCmd-3.0.0.250-osx.app.zip
http://cdn.sencha.com/senchacmd/SenchaCmd-3.0.0.250-windows.exe.zip
You are developing with Sencha Touch and Eclipse? You want to have code completion and outline? ... Here I'll show you how to do it at no charge to you.
This tutorial works also for ExtJS developer, at least I tested it with ExtJS 4.x before. But actually I don't know if the required *.jsb3 file is still included their archives. May someone can confirm this?

Requirements:
  • Working installation of Eclipse with Aptana Studio Plug-in (tested with Eclipse Juno Service Release 2 and Aptana Studio 3.4.0)
  • Unzipped Sencha Touch 2.x.x (tested with Sencha Touch 2.2.1)
  • *.jsb3 file *
* Since .jsb3 file is no more included in the Sencha Touch 2.2.1 archive (I guess they wanna sell you the Sencha Architect instead), you can download it here directly:
Download Sencha Touch .jsb3

For the case you are new to Aptana, I can suggest you to watch the following video tutorial first.

In the next steps I will show you how to install and configure your Spket IDE:
  1. Download and copy the *.jsb3 file into the root directory of your extracted Sencha Touch archive (as a sibling of src)
  2. Start Eclipse.
  3. Goto Help > Install New Software
  4. Click the "add" button
    1. Name: Spket IDE
    2. Location: http://www.agpad.com/update/
  5. Select the Spket IDE Node and click the "Next" button (See Image1). Follow the installation steps.
  6. Restart Eclipse.
  7. In Eclipse, Windows > Preferences or just press  + ,
  8. Select "Spket" > "JavaScript Profile preference" page to display the installed JavaScript Profiles.
  9. Click the "New.." button. In the Name field, type "Sencha Touch" as the name for the new profile. Click "OK".
  10. Click the "Add Library" button. From the Library drop-down list, select "ExtJS". Click "OK".
  11. Click the "Add File" button, choose the *.jsb3 file, which you copied to the Sencha Touch root folder before (See step 1).
  12. Check all the available select boxes in the created profile.
  13. Select the Ext profile created in step 9, click the "Default" button. This makes it to the default profile for all your project.
  14. Click "OK" to save the preferences.
  15. Open your javascript file with the Spket JavaScript Editor. You can set Spket JavaScript Editor as the default editor. "Windows" > "Preferences" or just press  + ,"General" > "Editors" > "File Associations". Select the filetype "*.js". In associated editors select the Spket JavaScript Editor and press the "Default" button. See Image2.
  16. When you type "Ext.de" and press STRTG + SPACE your code should get completed.
  17. Done.