Developing Mobile Applications with Force.com and Sencha Touch: Part 1

Return to Series Home

The Sencha Touch framework provides a full set of UI controls, over 300 built-in icons, full support for theming, MVC support, data binding, and more. It is designed to take advantage of hardware acceleration, and includes a native packager with native device APIs that work on both iOS and Android. This is all topped off with online documentation, screencasts, and other learning resources, including examples of all components, plus full reference applications.

Sencha Touch uses minimal HTML in the hosting page and is dependent upon pure JavaScript for all of its features and functionality. This suggests that a developer would require a deeper knowledge of JavaScript, yet, one of the greatest benefits of Sencha Touch is that it "tames" JavaScript with its hierarchical class system, providing a structure to ease development and maintenance. It is a perfect fit for building enterprise mobile applications, as it promotes a component-based modular approach, resulting in an organized code base. This helps to keep applications manageable as they grow, and enables collaborative development.

A Sencha Touch application can be deployed within Visualforce as raw JavaScript, or with other architectural approaches available, depending on the desired modularity and optimization required by your application. Sencha’s libraries are available from a hosted cloud server, or Sencha's SDK builder tools can compile and minify an application into highly compressed and optimized JavaScript files that can then be easily deployed as Force.com static resources. Sencha also provides a mechanism to patch and update mobile JavaScript applications in a very smart and efficient manner after they are cached locally on a mobile device. The Sencha MVC Data Package can integrate directly with Apex controller @RemoteAction methods, as well as with the Force.com REST API, providing options for highly scalable and maintainable data transport mechanisms.

Start Simple, then Iterate

To help you get to know the framework, we're going to build a very simple mobile application using Sencha Touch with Visualforce. Our application will not require any user authentication; we'll expect our users to login from a mobile phone browser directly to Salesforce. Nor will we require you to download, install or configure any Sencha SDKs or toolsets; all of our development will be performed in the cloud.

Our application will be a one page mobile web application that displays Lead information. We'll name our application PocketCRM, and slowly build it out over a number of iterative steps. Initially, our application will work with mock data provided by hardcoded JSON, rather than fetching records from a Force.com controller or web service. Once everything else is working, we’ll swap out that JSON and call a simple Apex controller method to serve up Lead records directly from Salesforce. We’ll also make sure to include a unit test in our controller class, both to insure our Apex logic is working as expected before we try to bind it to our Sencha data store, and because it is a Force.com requirement to provide code coverage for our classes.

In a followup article, we will extend our application to include a drill-down form for our Leads, and add some Create, Read, Update, Delete (CRUD), and validation capability on the client, and we’ll extend our Apex controller to bind @RemoteAction methods to our data proxy to serve up and process the data from the server.

In subsequent iterations, we would expect to migrate our Sencha Touch application from its Visualforce Component host into a local development environment so we can explore and take advantage of the MVC file and folder development paradigm. This would allow us to deliver an optimized and minified JavaScript application file deployed as a Force.com cached static resource.

Let's Go!

Our initial objective is to gain a general understanding of the Sencha Touch framework and the benefit of its structured class system and MVC implementation model. It is most important that you perform your development work in Safari as it supports WebKit and will display the touch-style interface on your desktop. It will also allow calling unsecured JavaScript and CSS libraries on the Sencha.io cloud, (Chrome might not allow them).

From start to finish, our Force.com Sencha Touch application will be contained in just four Salesforce metadata items:

  • A custom Visualforce component to contain our JavaScript application.
  • A custom Visualforce component to contain our application’s custom CSS styles.
  • A custom Visualforce page to host our application components.
  • A custom Apex controller class to manage the data processing.

Step 1: Get a Force.com Developer Edition Org

If you don't already have a salesforce.com development org that you can use, register to get your own free Developer Edition org. Once there, enter your information and create a username; you will be sent an email with login instructions.

If you know little or nothing about Force.com development, you'll want to familiarize yourself with the basics. You can browse the Getting Started area where you'll find a ton of material. Your best bet is to spend some time with the Workbook tutorials, and, in particular, to work through the Force.com Workbook and the Visualforce Workbook.

You can develop your code from the Setup area (click your name -> Setup) using Develop -> Pages and Develop -> Components, or you can use the Developer Console. If you have experience with the Force.com IDE and Eclipse, you are certainly welcome to use it for your development environment; any of these will do. Assuming you're all set with your Force.com development environment, you can jump to the next step.

Step 2: Understand the Sencha Touch Libraries

One of the more challenging aspects of getting started with any new platform or framework can be setting up a local development environment. However, since we're building on the Force.com cloud, and are able to reference Sencha Touch libraries from the Sencha.io cloud, we simply don’t have to bother! Later, you might want to setup a local development environment by downloading the libraries and tools, and perhaps maintain your own versions of the Sencha libraries as static resources in your Salesforce orgs. However, for our immediate purposes, we’ll reference the libraries across the web.

Step 3: Build a Visualforce Custom Component to Host Our JavaScript Application

We're going to build our JavaScript application code inside a custom Visualforce component which will subsequently be hosted in a Visualforce Page. Launch the Force.com editor of your choice and create a new Visualforce Component. Name it PocketCRM_App and replace the starting code stub with the following code. Make sure you contain all of your JavaScript code inside the Visualforce <apex:component> and <script> tags, and take special care to close all braces {} and parentheses ():

<apex:component>
    <script type="text/javascript">
        //==============================================================================================
        //APPLICATION
        //The Application class is the entry point into your Sencha Touch application.
        //==============================================================================================
        Ext.application({
            name: "PocketCRM",
            //The application's startup routine once all components are loaded.
            launch: function () {

                //Instantiate your main list view for Leads.
                var mainView = Ext.create('Ext.Panel', {
                    fullscreen: true,
                    html: 'Welcome to PocketCRM!'
                });

                //Launch the primary fullscreen view and pass in the main view.
                Ext.Viewport.add([mainView]);
            }
        });
    </script>
</apex:component>

This initial JavaScript component is the launch point of our mobile web application. It contains a name property, instantiates a Sencha Touch Panel component to display a simple HTML message, and loads that component to the application's Viewport, (the container for the application's user interface). We will return here later to add additional components as we build out our application, but for now, this will act as our initial application shell.

Step 4: Build a Host Visualforce Page

Now we're going to build a host Visualforce page that will contain our custom Visualforce component, so launch the editor of your choice and create a new Visualforce page. Name it PocketCRM and replace the existing code with the following Visualforce code:

<apex:page docType="html-5.0" showHeader="false" standardStylesheets="false" cache="false">
    
    <head>
        <meta charset="UTF-8" />
        <title>Pocket CRM</title>

        <!-- Use the Visualforce tags for scripts and stylesheets rather than their HTML counterparts -->
        <apex:includeScript value="http://cdn.sencha.io/try/touch/2.0.1/sencha-touch-all.js"  /> 
        <apex:stylesheet value="http://cdn.sencha.io/try/touch/2.0.1/resources/css/sencha-touch.css"  /> 

        <!-- Our custom Visualforce component containing our Sencha Touch application -->
        <c:PocketCRM_App />
    </head>
    
    <body>
        <!-- An animated image that displays while loading -->
        <div id="appLoadingIndicator">
            <div></div>
            <div></div>
            <div></div>
        </div>
    </body>
</apex:page>

There's not much to this page at all. Note the doctype="html-5.0" in the <apex:page> tag, and the references to the Sencha Touch libraries on the web. Also, note the references to the custom Visualforce component containing your JavaScript application. The appLoadingIndicator is a graphic provided by the framework that will display an animated icon as our application loads.

Now let’s see if it works by entering the name of the Visualforce page in the URL address bar of your browser, which will look something like this, (depending on your Salesforce server instance):


SenchaForcePart1 Image01.png


After you press Enter, the server will redirect to display the Visualforce page, the URL will change a little, (again it depends on your home server):


SenchaForcePart1 Image02.png


If your page and component were built correctly, and you are successfully referencing the Sencha Touch libraries, your application should load and your screen should appear like this:


SenchaForcePart1 Image03.png


If it does, congratulations! You now have a functioning Sencha Touch application running in Visualforce on the Force.com cloud. If not, you'll have to troubleshoot what went wrong, probably starting with a review of the Sencha Touch library paths, as well as the page and component code to make sure everything is correct. You can also use any number of client side tools to debug your JavaScript in a browser.

Other problems that could be preventing the application from coming up:

  • Are you using Safari? Remember that your browser must support WebKit (Firefox does not) and Chrome (which does) will not easily load the Sencha libraries that we're currently referencing on Sencha's CDN cloud servers because they are not secure content (not called with HTTPS). Safari is one of the best browsers to use for our purposes, and also provides great developer tools for debugging client side JavaScript. You can download it from the Apple download site.
  • Did you wait long enough for the page to load? It might take a few seconds to a minute for the screen to update, depending on your connection speed and hardware. We're using the full Sencha library, which is not minified and could require a noticeable initial load time. Later, we'll review the processes for optimizing and minifying both your application and the libraries, but for our purposes, it will be easier to work with the full version in this manner.
  • Is there something wrong with the code? Check what you copied and pasted, and how you named the components in your salesforce.com org. You can also reference the completed application for Part 1 here at Github.

Step 5: Build a Visualforce Custom Component to Host Our Application-Specific Styles

We're going to add a second custom Visualforce component to contain our custom Sencha Touch application styles. Normally, this CSS content would be managed in a CSS file and uploaded as a static resource, but I suggest maintaining these styles as a component during development as it is easier to make modifications on the fly from within the Force.com development environments; they can be refactored into a bonafide CSS file later.

So, create a new Visualforce Component named PocketCRM_CSS and replace the existing Visualforce code stub with the following:

<apex:component>
    <style type="text/css">
        /**
        * Example of an initial loading indicator.
        * It is recommended to keep this as minimal as possible to provide instant feedback
        * while other resources are still being loaded for the first time
        */
        html, body {
            height: 100%;
            background-color: #1985D0
        }
        #appLoadingIndicator {
            position: absolute;
            top: 50%;
            margin-top: -15px;
            text-align: center;
            width: 100%;
            height: 30px;
            -webkit-animation-name: appLoadingIndicator;
            -webkit-animation-duration: 0.5s;
            -webkit-animation-iteration-count: infinite;
            -webkit-animation-direction: linear;
        }
        #appLoadingIndicator > * {
            background-color: #FFFFFF;
            display: inline-block;
            height: 30px;
            -webkit-border-radius: 15px;
            margin: 0 5px;
            width: 30px;
            opacity: 0.8;
        }
        @-webkit-keyframes appLoadingIndicator {
            0% {
                opacity: 0.8
            }
            50% {
                opacity: 0
            }
            100% {
                opacity: 0.8
            }
        }
        /**
        * PocketCRM Custom styles
        */
        .x-title {
            padding: 0 .3em;
        }
        .x-title .x-innerhtml {
            padding: 0;
        }
        /* Increase height of list item so title and narrative lines fit */
        .x-list .x-list-item .x-list-item-label {
            min-height: 3.5em!important;
        }
        /* Move up the disclosure button to account for the list item height increase */
        .x-list .x-list-disclosure {
            position: absolute;
            bottom: 0.85em;
            right: 0.44em;
        }
        .list-item-line-1 {
            float:left;
            width:100%;
            font-size:90%;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            padding-right:25px;
            line-height:150%;
        }
        .list-item-line-2 {
            float:left;
            width:95%;
            color:#666666;
            font-size:80%;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            padding-right:25px;
        }
        .x-item-selected .list-item-name {
            color:#ffffff;
        }
        .x-item-selected .list-item-email {
            color:#ffffff;
        }
        .leads-list-empty-text {
            padding:10px;
        }
    </style>
</apex:component>

These custom styles will support our application going forward. Don't worry if you aren't very familiar with CSS. All we’re doing is setting some styles for our own custom application content, as well as some commonly used Sencha Touch JavaScript components, including the initial animated loader image. Notice the class references, such as .x-list, .x-list-item and .x-list-item-label, as they are part of the Sencha-structured framework classes. Sencha Touch also provides a powerful but friendly theming engine for your applications that leverages Sass (Syntactically Awesome StyleSheets), a stylesheet language that you can delve into later.

Add a reference to this component in your Visualforce page above the reference to PocketCRM_App as follows:

...
 
    <c:PocketCRM_Css />
    <c:PocketCRM_App />
 
</head>

Launch your page again, and make sure it displays properly; the appearance will not change.

Build Out the Sencha Touch Application

Now that we have a functioning application shell that we can easily test, let's build it out one JavaScript component at a time. We'll use an iterative and incremental Agile style development approach, as we add and change our code modules. In this manner, we can quickly test and repair any changes that break our functioning application. Yes, you can do test-driven development with JavaScript, including unit tests, but that is beyond the scope of this article.

Step 1: Add a Data Store

The first component we will add to our application is a Data Store, part of the Sencha Data Package, a collection of components designed to manage loading and saving of all data in an application. The Store is nothing more than an in-memory database of a collection of records, and is dependent upon a defined Model that provides the schema and any additional data-related details. In our case, our model will contain the schema of our salesforce.com Lead standard object, and we'll begin with just a small subset of the available fields.

Initially, our store will contain static mock data in JSON format so that we can build our application and user interface without having to focus on authentication and data transport functionality.

Go back to the PocketCRM_App component and add the following code (insert this JavaScript just after the Ext.application code block):

//==============================================================================================
//STORES
//Stored serve as the client-side cache of your data; they loading data into your app's views. 
//==============================================================================================
//The Lead Store, this version will simply load with mock JSON data.
Ext.define("PocketCRM.store.Leads", {
    extend: "Ext.data.Store",
    requires: "Ext.data.proxy.LocalStorage",

    config: {

        model: "PocketCRM.model.Lead",

        //You can type the following Apex code in the Execute Anonymous window to 
        //generate JSON which can then be cut and paste in the component. You can  
        //use the Eclipse Force.com IDE Schema Browser or the Workbench to build SOQL
        //
        // List<Lead> leadList = 
        //  [SELECT FirstName,LastName,Company,Title,Phone,Email,Status FROM Lead]; 
        //  
        // system.debug(JSON.serializePretty(leadList));
        //
        // While you can easily remove the 'attributes' node, it will be ignored.

        data: [
            {
            "attributes": {
                "type": "Lead",
                "url": "/services/data/v25.0/sobjects/Lead/00QA0000004wQTZMA2"
            },
            "FirstName": "Bertha",
            "LastName": "Boxer",
            "Company": "Farmers Coop. of Florida",
            "Title": "Director of Vendor Relations",
            "Phone": "(850) 644-4200",
            "Email": "bertha@fcof.net",
            "Status": "Working - Contacted"
        }, {
            "attributes": {
                "type": "Lead",
                "url": "/services/data/v25.0/sobjects/Lead/00QA0000004wQTaMAM"
            },
            "FirstName": "Phyllis",
            "LastName": "Cotton",
            "Company": "Abbott Insurance",
            "Title": "CFO",
            "Phone": "(703) 757-1000",
            "Email": "pcotton@abbottins.net",
            "Status": "Open - Not Contacted"
        }, {
            "attributes": {
                "type": "Lead",
                "url": "/services/data/v25.0/sobjects/Lead/00QA0000004wQTbMAM"
            },
            "FirstName": "Jeff",
            "LastName": "Glimpse",
            "Company": "Jackson Controls",
            "Title": "SVP, Procurement",
            "Phone": "886-2-25474189",
            "Email": "jeffg@jackson.com",
            "Status": "Open - Not Contacted"
        }
        ],

        //Create a grouping; be certain to use a field with content or you'll get errors!
        groupField: 'Status',
        groupDir: 'ASC',

        //Create additional sorts for within the Group.
        sorters: [
            {
            property: 'LastName',
            direction: 'ASC'
        },
            {
            property: 'FirstName',
            direction: 'ASC'
        }
        ]
    }
});

After you have added the code, refresh your Visualforce page and make sure it displays exactly as before. There will be no change to the display, but you will want to insure that you have not introduced any JavaScript errors that could cause the page to fail.

Looking at the code, note the naming convention of the component PocketCRM.store.Leads. This is a naming pattern that supports the hierarchical class structure of the framework. Sencha uses a namespace (the application name), plus a categorization of the various component layers (store, model, view, etc.), and finally, the name of the component itself.

This organizational hierarchy is also used with a file and folder pattern when developing Sencha Touch applications on a local computer, and we'll look more closely at that development methodology in a subsequent posting. For now, just note the naming convention as you'll see it over and over again while we add components to our application.

Step 2: Add a Data Model

Now we'll add the Model that will define the schema and details of our Salesforce data object. A model represents some data entity that your application requires. In the case of our CRM mobile application, it could be Lead, Contact, Account, or it could also be information about the User and Organization. It is primarily the schema of the object as a collection of fields, but it provides additional sophisticated functionality.

Add the following code to the PocketCRM_App component. I like to place the Model code above the Store, but it doesn't really matter as there is no enforced sequence for your JavaScript components, (another benefit of the Sencha Touch framework.)

It's most important to keep in mind that for the models of your Sencha app field level security on your target sObject must be set to both read and write for all users or else you may get JavaScript errors. You can indeed take a more sophisticated approach later and leverage the Describe capability in Apex to dynamically create JavaScript models based on running user security, but that's a level of complexity well beyond the scope of this tutorial!

//==============================================================================================  
//MODELS
//Models are the objects on your application.
//==============================================================================================  
//The Lead model will include whatever fields are necssary to manage.
Ext.define("PocketCRM.model.Lead", {
    extend: "Ext.data.Model",

    config: {

        idProperty: 'id',
        fields: [
        {
            name: 'id',
            type: 'string'
        },
        {
            name: 'FirstName',
            type: 'string',
            required: true
        },
        {
            name: 'LastName',
            type: 'string',
            required: true
        },
        {
            name: 'Company',
            type: 'string'
        },
        {
            name: 'Title',
            type: 'string'
        },
        {
            name: 'Phone',
            type: 'string',
            required: true
        },
        {
            name: 'Email',
            type: 'string',
            required: true
        }, 
        //Status must contain a value as our grouping 
        //on this field requires it not be null.
        {
            name: 'Status',
            type: 'string',
            required: true
        }, //This is a derived field using an anonymous 'convert' 
           //anonymous function to calculate a string value.
        {
            name: 'FullName',
            convert: function (value, record) {
                var fn = record.get('FirstName');
                var ln = record.get('LastName');
                return fn + " " + ln;
            }
        },
        ],
    },
});

Again, you'll note the naming convention of the model PocketCRM.model.Lead, and the fields array containing the description of the small subset of Lead fields that we will begin with.

We will use the Status field for grouping in our list, so it must not contain any null values. This should work fine as Status is a picklist field and required in the Lead standard object in Salesforce.

We will use a convert() function for the FullName field, which is not a field on the Lead object at all, but rather a derived field in our application's model, calculated by the embedded function. There is already a Name field in the Salesforce Lead object that does the same thing, and we'll re-factor later to use it. Right now, we just want to show what you can do inside a Sencha Touch Model with convert(). Also, notice the required property on some fields that will be used by the editable view we will build in the next iteration, and we will also identify which field is the ID for the record.

Once again, after you have added the code, refresh your Visualforce page and make sure it displays exactly as before.

Step 3: Add a Controller for the List View

Before we can build our user interface to display our Leads, we have to build the Controller component. You've just built out the Model component for the Lead object, and the Store component that will eventually contain data fetched from your Salesforce org, (but currently contains only mock data in JSON). Now we must build our client side Controller that will manage the View (user interface), and will provide the Model (data) from the Store. The Controller will also eventually handle user events emitted from the View.

You might be familiar with the Model-View-Controller (MVC) pattern. In any custom Force.com application, our Visualforce pages represent the Views, our Apex code acts as custom Controllers (or Controller Extension to a main page Controller), and our Salesforce objects act as our Models. We build our Sencha Touch applications using the same pattern, but our MVC components exist only in the client JavaScript application, and run entirely on the device rather than on a server.

Add the following code to the PocketCRM_App component. I like to place the Controller code above the Model, but again it doesn't really matter:

//==============================================================================================
//CONTROLLERS
//Controllers manage the communication of your application and the coordination between the
//views and the model; they listen for the events emitted by the views and react accordingly.
//==============================================================================================    
//The controller for the Leads list view
Ext.define("PocketCRM.controller.Leads", {
    extend: "Ext.app.Controller",

    config: {},

    // Base Class functions.
    launch: function () {
        console.log("launch");
        this.callParent(arguments);

        //Load up the Store associated with the controller and its views. 
        console.log("load Leads");
        var leadsStore = Ext.getStore("Leads");
        leadsStore.load();

    },

    init: function () {
        this.callParent(arguments);
        console.log("init");
    }

});

The only code to take special note of is the load of the Lead store; we are not configuring any other functionality at this time. You'll also notice that we occasionally write out debug messages with console.log(). This is a common JavaScript debugging practice and very helpful during development, but you'll need to use a browser with developer tools allowing client side JavaScript debugging to see the messages.

Once again, refresh your Visualforce page and make sure it displays exactly as before.

Step 4: Add a View for the List

Now the fun truly begins as we add the View that will display a list of our Leads in a touch UI.

Add the following code above the Controller component:

//==============================================================================================
//VIEWS
//Views display data to your users and gather input from them; 
//they also emit events about your user interaction.
//==============================================================================================
//The Lead list view.
Ext.define("PocketCRM.view.LeadsList", {
    extend: "Ext.Container",

    //It uses the base list class.
    requires: "Ext.dataview.List",
    alias: "widget.leadslistview",

    config: {

        //Take up the full space available in the parent container.
        layout: {
            type: 'fit'
        },

        //Add the components to include within the list view. 
        items: [
            {
            //A simple top title bar. 
            xtype: "titlebar",
            title: "PocketCRM: Leads",
            docked: "top",
        },
            {
            //The main list and its properties. 
            xtype: "list",
            store: "Leads",
            itemId: "leadsList",
            onItemDisclosure: false,
            grouped: true,
            disableSelection: false,

            //The template for display if the Store is empty of records.
            //Note the style to control visual presentation.
            loadingText: "Loading Leads...",
            emptyText: '<div class="leads-list-empty-text">No leads found.</div>',

            //The template for the display of each list item representing one record.
            //One row will display for each record in the data Store.
            //The fields referenced are from the entity's Model. 
            itemTpl: '<div class="list-item-line-main">{LastName}, {FirstName}</div>' + '<div class="list-item-line-detail">{Company}</div>' + '<div class="list-item-line-detail">{Title} - Phone: {Phone} </div>' + '<div class="list-item-line-detail">{Email}</div>',
        }],
    }
});

This view provides the only display in our application for this iteration. It will fill the entire screen and is divided into two components configured in the items array. The first component is a simple TitleBar, with nothing more than a title; later we'll add some buttons to this component. The second component is the List that will display our Leads grouped by Status. Note that you only see the property grouped set to true, but no information regarding what field the data is grouped on. That information is configured in the Store, go back and find it.

The two itemTpl templates define how each Lead item (record) should be displayed in the list. One is for an empty list of no records, the other for when there is record data to display. Note the styles from our custom style sheet that we built earlier into our Visualforce custom component, PocketCRM_CSS.

Once again, refresh your Visualforce page - it should continue to display exactly as before if everything is working, and you'll notice that no list of records is displayed. Why not?

Step 5: Complete the Application

Even though we created the Model, View, and Controller components, we have to tie them all together, which we will do in our main application component. Go back to the Application component now and replace the JavaScript code with the following:

Ext.application({
    name: "PocketCRM",

    //Load the various MVC components into memory.
    models: ["Lead"],
    stores: ["Leads"],
    controllers: ["Leads"],
    views: ["LeadsList"],

    //The application's startup routine once all components are loaded.
    launch: function () {

        //Instantiate your main list view for Leads.
        var leadsListView = {
            xtype: "leadslistview"
        };

        //Launch the primary fullscreen view and pass in the list view.
        Ext.Viewport.add([leadsListView]);

    }

});

Note the new code where we identify the various MVC components to be loaded when the application launches. In addition, note the launch function where we instantiate the leadsListView and add it to the application's Viewport, which provides the main UI for our application.

Now refresh your page and you should see the List display as follows:

SenchaForcePart1 Image04.png

Pretty cool! We only have three mock Lead records in the Store, but it's easy to add as many as you want.

Step 6: Build Out Your Own JSON Mock Lead Data

You can generate JSON for your own leads with just two lines of Apex code from an Execute Anonymous window, either in the Force.com IDE or the Developer Console. Execute the following code and then grab the JSON output from the debug log and insert it into the Store component data configuration, (be careful to check for proper comma and closing brace placement!):

//Run this code in an APEX Execute Anonymous window:
List<Lead> leadList = [SELECT FirstName ,LastName ,Company ,Title ,Phone ,Email ,Status FROM Lead LIMIT 5];
system.debug(JSON.serializePretty(leadList));

/*Your results will be as follows in the DEBUG LOG.
*Find the USER_DEBUG line and copy all the JSON 
*starting with the '[' delimiter thru the ending ']' delimiter
*and paste into your data store as the data content.  
*The 'attributes' content is not used by Sencha, but you 
*don't have to remove them as they will simply be ignored.
*Output on the DEBUG line will look something like 
*this for five records as set by the SOQL LIMIT:

11:26:46.060 (60490000)|USER_DEBUG|[2]|DEBUG|[ {
  "attributes" : {
    "type" : "Lead",
    "url" : "/services/data/v26.0/sobjects/Lead/00Q5000000dSItmEAG"
  },
  "FirstName" : "Test",
  "LastName" : "Lead 088",
  "Company" : "Test Company 088",
  "Title" : "Test Title",
  "Phone" : "555-555-5555",
  "Email" : "tlead088@testco.com",
  "Status" : "Open - Not Contacted"
}, {
  "attributes" : {
    "type" : "Lead",
    "url" : "/services/data/v26.0/sobjects/Lead/00Q5000000dSItnEAG"
  },
  "FirstName" : "Test",
  "LastName" : "Lead 089",
  "Company" : "Test Company 089",
  "Title" : "Test Title",
  "Phone" : "555-555-5555",
  "Email" : "tlead089@testco.com",
  "Status" : "Open - Not Contacted"
}, {
  "attributes" : {
    "type" : "Lead",
    "url" : "/services/data/v26.0/sobjects/Lead/00Q5000000dSItoEAG"
  },
  "FirstName" : "Test",
  "LastName" : "Lead 090",
  "Company" : "Test Company 090",
  "Title" : "Test Title",
  "Phone" : "555-555-5555",
  "Email" : "tlead090@testco.com",
  "Status" : "Open - Not Contacted"
}, {
  "attributes" : {
    "type" : "Lead",
    "url" : "/services/data/v26.0/sobjects/Lead/00Q5000000dSItpEAG"
  },
  "FirstName" : "Test",
  "LastName" : "Lead 091",
  "Company" : "Test Company 091",
  "Title" : "Test Title",
  "Phone" : "555-555-5555",
  "Email" : "tlead091@testco.com",
  "Status" : "Open - Not Contacted"
}, {
  "attributes" : {
    "type" : "Lead",
    "url" : "/services/data/v26.0/sobjects/Lead/00Q5000000dSItqEAG"
  },
  "FirstName" : "Test",
  "LastName" : "Lead 092",
  "Company" : "Test Company 092",
  "Title" : "Test Title",
  "Phone" : "555-555-5555",
  "Email" : "tlead092@testco.com",
  "Status" : "Open - Not Contacted"
} ]

*/

Don't worry about the 'attribute' node generated for each record as it will be ignored by the Sencha Touch store.

Replace Your Mock Data With The Real Thing

Now that everything is working on the client side, we’re going to swap out the mock JSON data hard wired into the data store. We’ll replace it with Visualforce data binding to a simple custom Apex controller class ‘getter’ method that will fetch Lead records from your salesforce.com org as the page loads. We’ll also make sure to include an Apex test method in the controller class as we want to insure that our class is performing correctly before trying to bind it. We also want to follow development best practices and prepare for the Salesforce requirement of maximum test coverage for deployment into a production Force.com environment.

So, create a new Apex Class named PocketCRMLeadController and replace the code stub with the following:

public class PocketCRMLeadController {
    private string leads;

    //Constructor.
    public PocketCRMLeadController() {

        //Fetch a limited set of Leads to return to the Sencha Data Store on load. 
        List < Lead > leadsList = [SELECT
                                              FirstName
                                              , LastName
                                              , Company
                                              , Title
                                              , Phone
                                              , Email
                                              , Status 
                                            FROM Lead LIMIT 25];

        //Serialize the list as JSON and assign to the private string member.
        leads = JSON.serialize(leadsList);
        system.debug('Leads as JSON: ' + leads);

    }

    //Public getter method to return the Leads as JSON to the view.
    public String getLeads() {

        return leads;

    }

    //UnitTest for code coverage.
    testMethod static void canTestConstruction() {

        //Build some mock data for the test.
        List < Lead > leadList = new List < Lead > ();
        for (Integer i = 0; i < 10; i++) {
            leadList.add(new Lead(
            Firstname = 'Test', Lastname = 'Lead' + String.valueOf(i), Company = 'Acme', Status = 'Open - Not Contacted'));
        }

        //Insert mock leads
        INSERT leadList;

        //Instantiate the controller which will fetch the Leads.
        PocketCRMLeadController c = new PocketCRMLeadController();
        system.assertNotEquals(c.getLeads(), null);

        //Output to the debug for visual confirmation during testing.    
        system.debug(leadList);
        system.debug(c.getLeads());
    }

}

Note the constructor of this class simply performs a SOQL query to fetch a limited set of Lead records into a local list variable, and then calls the JSON.serialize() system method to convert that list into a JSON string stored in a private class member.

The public ‘getter’ method getLeads() will be used to bind the JSON string from the private member to the data property in the Sencha Touch store when the page first loads. Also note the test method in the class as mentioned above. Make sure to run the test to verify that your class is working before trying to bind it to your Sencha Touch component. Tests can be run from the Setup -> Develop -> Classes administration pages. The test will also print out the set of mock leads created in the test method to the debug log where you can perform a visual validation, always a good practice.

Now let’s make the modification to bind our controller getter method to the data store in the Sencha Touch component. Go back to PocketCRM_App and make two changes.

First, you must add a controller attribute to reference the new custom Apex controller class in the <apex:component> tag at the top of PocketCRM_App:

<apex:component controller="PocketCRMLeadController" >

Next, replace the JavaScript code in the PocketCRM.store.Leads with the following code to remove the mock JSON data and replace it with a data binding expression to the controller’s getter method. Remember: even though the method name is getLeads() we bind to it as {!Leads}.

//The Lead Store, this version will simply load with mock JSON data.
Ext.define("PocketCRM.store.Leads", {
    extend: "Ext.data.Store",
    requires: "Ext.data.proxy.LocalStorage",

    config: {

        model: "PocketCRM.model.Lead",

        //Fetch the data from the custom Apex controller method 
        //which will return a simple list of Leads as JSON on load.  
        data: {!Leads},

        //Create a grouping; be certain to use a field with content or you'll get errors!
        groupField: "Status",
        groupDir: "ASC",

        //Create additional sorts for within the Group.
        sorters: [{
            property: 'LastName',
            direction: 'ASC'
        }, {
            property: 'FirstName',
            direction: 'ASC'
        }]
    }

});

Now refresh your page and you should see the List display again, but this time the data should match a set of Leads from your Salesforce database.

Demo Version One of PocketCRM

So how do you launch the application from your iPhone? When working in development mode, you can launch a mobile browser and navigate to the Salesforce login URL where a mobile login page will display since Salesforce can recognize the device's type by USER_AGENT.

Log into your development application as usual. Of course, your Salesforce org will display in a very small presentation, but once logged in you can change the URL to add the name of the Apex page, and once the page is displayed, it can be saved to the Home screen or as a bookmark:

https://c.{SERVER_NAME}.visual.force.com/apex/PocketCRM

Your Visualforce page should run and launch your Sencha Touch application. You'll notice that it takes more than a few seconds to load as it downloads the library files, which are not small. As mentioned above, you will typically develop with the full libraries, but you can optimize them later for deployment using the Sencha builder tools that will compress and minify all your code for maximum performance.

When you're ready to put your mobile application into production, it can be launched through a Force.com Site, which will expose your mobile Visualforce pages in a secure and sensible manner. Your users will simply need to navigate to a custom domain that you can configure with your company name, (and keep in mind that a Sencha Touch Visualforce application can also be used to create a mobile website for your company too!)

Once launched, users can save the link on their device home screen to launch at the click of an icon. They can also choose to store their user and password on the device to auto-popluate the login form whenever they launch the app, however please note this is NOT a secure practice unless the device is secured with a PIN!

Summary

So let's recap what we have accomplished:

  1. We prepared our Force.com development environment and identified that Sencha Touch libraries could be accessed over the web.
  2. We built two Visualforce components to host our custom JavaScript application as well as our custom CSS styles.
  3. We built a Visualforce page to reference the libraries and host our application components.
  4. We built our Sencha Touch custom JavaScript modules for Application, Store, Model, Controller, and View.
  5. We built out an Apex controller to fetch data from the salesforce.com database and pass it into the data store on load, and built a test method to insure its functionality before binding it to the Sencha Touch component. Then we swapped it for the hardcoded JSON in the Sencha Touch data store that we initially used to develop with.
  6. We tested continuously as we built incrementally, and were able to demo when completed in true Agile fashion.

You can find the full code for the completed application for Part 1 here at Github.

Step Back for a Mobile Perspective

Mobile applications are often most successful when they provide solutions for one or more small, (though not necessarily unimportant,) tasks that need to be performed anywhere and anytime. This is perfect with regard to salesforce.com implementations, where often there can be a multitude of such operations or user interactions. You don’t have to build large or complex mobile applications to benefit greatly from a mobile addition to your org, but you do need to think carefully about what kind of tasks would be most beneficial to be managed from a mobile device by your user community. For further perspective, I suggest you read up on mobile application concepts, and a good place to start is with Apple’s iOS Human Interface Guidelines.

Plan Ahead For Our Next Iteration (and do some Homework)

In Part 2, our next iteration, we'll build a new form view and add additional controller event management to allow for CRUD operations on our Leads. We’ll also build out the Apex controller for more data management functionality, adding @RemoteAction methods to bind to a new Sencha Touch component, called a proxy, in our data store.

In the meantime, you might want to bone up on your Sencha Touch concepts by watching some videos, playing with and dissecting some samples, and reading through some of the great guidance documentation.

Here are some links to follow:

  1. Dig deep into the Sencha Touch website
  2. Check out the Sencha Touch online documentation and guidance pages, with tutorials, videos, and full API documentation - (make sure to watch the [videos] from the last SenchaCon conference found in the Guidance section).
  3. Follow the MiamiCoder's BLOG - lots of expert tutorials on Sencha Touch, as well as jQuery and other frameworks.
  4. Follow Pat Patterson on Twitter, just one of the great Force.com Developer Evangelists who has really had his head in the mobile cloud.
  5. And of course, dig into all the great mobile related content on the developer.force.com portal.

About the Author

Don Robins has been building custom business applications with framework-based architectures for over two decades. He found his way into Force.com as a consultant and architect in 2009, and has recently been immersing himself in Force.com mobile integration. A salesforce.com Certified Advanced Developer and award winning Certified Instructor, he delivers all of the salesforce.com Developer Classes (DEV401, 501, 502, 531), both domestically and internationally, in both public and private workshops when not consulting or mentoring privately. His background and experience in the trenches as Developer, Architect, Team Lead, Tech Mentor, Certified Agile Scrum Master, and Developer Community Leader shapes his training and mentoring approach with developers of all skill levels, from novice to architect. Don is a principal of Outformations, Inc. and teaches under the banner of ForceMentor.com.