Sencha Inc. | HTML5 Apps

Blog

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

September 13, 2012 | Don Robins

Overview

If you are a Force.com or Sencha developer, you already understand the power and leverage of using a framework-based approach for building applications. You know from first-hand experience how patterns, pre-built functionality, metadata driven configuration, and a robust and structured architecture speed the creation of business solutions. But, the leverage of a framework-based approach gets tremendously greater when you can integrate multiple complementary frameworks. Mobile application development that brings Sencha Touch and Force.com together is a great example, and can yield great Force.com-based apps that can run on any touch device.

This series of articles will introduce you to the Sencha Touch mobile framework for building HTML5 applications with JavaScript, HTML and CSS, and will cover how to use it to build Force.com apps. Sencha Touch integrates very easily with Visualforce and the Force.com platform, and makes it relatively simple to build powerful business apps linked to a Salesforce or Force.com back-end. It renders a robust, touch-style user experience by manipulating the HTML Document Object Model (DOM) in a browser. Sencha Touch applications are typically written entirely in JavaScript, leveraging a rich hierarchical class system, a UI component library, and an MVC package.

The Sencha Touch application itself is typically hosted in an HTML home page, and all elements and components that render the touch style user interface are created dynamically in JavaScript, with the framework providing a consistent and predictable architectural foundation. You define, create and extend your classes from an object oriented component framework, providing for all aspects of a modern touch style user experience and powerful data management. A Visualforce page can host any HTML content, and is therefore a natural host for a Sencha Touch application.

A Richer JavaScript Framework

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 on-line 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 that provides 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 which can in turn 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.

Let's Build Something Simple and Grow its Complexity Incrementally

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 to display 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 may not allow them.)

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

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

Step 1: Prepare a Force.com Development Environment

If you don't already have a Salesforce.com development org that you can use, you'll want browse over to the Force.com Developer Portal and register to get your own free Developer Edition org. Once there, just click the Join Now link, 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 menu Develop->Pages and Develop->Components editors, 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: The Sencha Touch Libraries

One of the more challenging aspects of getting starting 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 able to reference Sencha Touch libraries from the Sencha.io Cloud, we simply don’t have to bother! Later, you may 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:

<apex:page docType="html-5.0" showHeader="false" standardStylesheets="false" cache="false"  >
<head>
<meta charset="UTF-8" />
<title>Pocket CRM</title>
<script src="http://cdn.sencha.io/try/touch/2.0.1/sencha-touch-all.js" />
<link rel="stylesheet" href="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 would look something like this, (depending on your Salesforce server instance):

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):

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:

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.

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.

Step 6: 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.

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 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 which would 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.

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.)

//==============================================================================================  
//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  },
 
//Although Status is a bonafide field on the Lead object, we want to insure 
                //there is a value as our grouping on this field requires it not be null.
                { name: 'Status', 
                        convert: function(value, record) {
                                    var st = record.get('Status');
                                    return st ? st : "No Status Assigned";
                              }
        },
 
      //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.

Note that we use a convert() JavaScript function on the Status field to insure a value if null. Because we will use it for grouping in our list, it must not contain any null values. This could be enforced in Force.com data, but it can be wise to add this additional layer of validation on the client side, and Sencha easily allows us to do so.

We also 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. Of course, we could alternatively provided a formula field from our Salesforce object to do the same thing, but we want to show what you can do inside a Sencha Touch Model. Also notice the required property on some fields that will be used by the editable view that we will build in the next iteration, and that we 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.

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 may be familiar with the Model-View-Controller (MVC) pattern. In any custom Force.com application, typically 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.

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.

First 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?

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:

Pretty cool! We only have three mock Lead records in the Store, but it's easy to add as many as you want. You can generate the 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 section's JSON, (be careful to check for proper comma and closing brace placement!):

List<Lead> leadList = [SELECT FirstName ,LastName ,Company ,Title ,Phone ,Email ,Status FROM Lead];
system.debug(JSON.serializePretty(leadList));

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

Step 7: 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
                                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. Note that if there is no status set on any lead, they will group under a Status of “No Status Assigned” derived by the Status field convert function in the model.

Step 8: Demo Version One of PocketCRM

So how do you launch the application from your iPhone? Launch a mobile browser and navigate to the Salesforce login URL where a mobile login page will display as Salesforce recognizes the device type. Login to 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, (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. You will typically develop with the full libraries, but you can optimize them later for deployment using the SDK builder tools which will compress and minify all your code for maximum performance.

Another option is to build a custom Salesforce Profile for a mobile user that automatically redirects all users of that profile to the mobile application when they log in. You can build a custom Application, and set the landing page to your application’s Visualforce page. Then set the profile to use that Application as the default. When users of that profile login to Salesforce, they will automatically be redirected to the mobile page. Of course, this won't work very well if they also need to access your org in a browser, but it's just an example of another way to redirect to your mobile application.

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.

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 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. You can read it now, here.

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.

Written by Don Robins
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.

Share this post:
Leave a reply

There are 23 responses. Add yours.

Kazuhiro Kotsutsumi

2 years ago

Step7 does not exist.

Don Robns

2 years ago

@Kazuhiro…thanks for the heads up! Too many late nights; no content is missing, we will correct the numbering shortly.  Don.

Kazuhiro Kotsutsumi

2 years ago

for Dan.

I thought that it was so.

Because I translate this blog, I repair it correctly there.
for exmaple: http://www.xenophy.com/javascript/3283

it’s np. Thank you for the article that is splendid.

@kotsutsumi

Zoltan, MAGDO

2 years ago

Hi Kazuhiro Kotsutsumi,

I’m only Sencha beginner/hobbyist ...

I open your very professional http://www.xenophy.com/javascript/3283
Have You some English/Francais/Espaniol/Romanian/Hungarian ... translation to your page ?
(Of course, I can use some translation robot… but it’s not main option ! )
I will highly apperiaciate If You have and you Sir can send to me one short link about translated pages.

Best regards,
Zoltán

Kazuhiro Kotsutsumi

2 years ago

Hi Zoltan, MAGDO.

I transtating now to Japanese.
Probably I will show it several hours later.

I’m Japan Sencha User Group Manager(organizer).
because I translate to Japanese, but I can’t understand Francais/Espaniol/Romanian/Hungarian etc, only English to Japanese.

By the way, I am a Japanese.

Zoltan, MAGDO

2 years ago

Thank You verrry much Kazuhiro !
English translation it’s very Good for me.
Have one Good day/evening/night.

Zoltan, MAGDO

2 years ago

I’m Hungarian/Romanian guy, So ?!
(53)

Kazuhiro Kotsutsumi

2 years ago

I translated it into Japanese.

http://www.xenophy.com/javascript/3385

Provision: Japan Sencha User Group
http://www.meetup.com/Japan-Sencha-User-Group/about/

Kazuhiro Kotsutsumi

2 years ago

Hi. Zoltan, MAGDO.

For all, I feel even slightly useful delightfully.
thx.

Zoltan, MAGDO

2 years ago

Your English it’s more better like my pilgrim eng.
Have fun,
Zoltán

Zoltan, MAGDO

2 years ago

I’m only Sencha fan/hobbyist.
it’s one great product !

Thank You for your time spended with me Kasuhiro…

Of course, maybe all will buy Sencha team license , I don’t know yet.

Best/Kind regards,
Zoltan

Kazuhiro Kotsutsumi

2 years ago

Zoltan, MAGDO

Thus I am all right.
Please only enjoy it.
I enjoy it, too.

thx.

Abdat El Mehdi

2 years ago

Can’t wait for next part.  Have you a date ?.

postanyadd

2 years ago

wow nice blog
English translation it’s very Good for me.
Have one Good day/evening/night.

Zoltan, MAGDO

2 years ago

Hi Abdat El Mehdi,
It’s end of week, rest time/days…
I think, You Sir, can wait some days for second/... part for this article.
I’m also very curious for the seqond/... parts of this article !

Best regards,
Zoltan
(Sencha fan/hobbyist)

Zoltan, MAGDO

2 years ago

Pls., take more easy bloggers,
This kind of work it’s not one day work/study !
You/We need to wait…

Thank You Don
(Sencha fan/hobbist)

Don Robns

2 years ago

We hope to post Part 2 shortly; thanks for your patience.

Jihane

2 years ago

Hello there, thank you for this tutorial, i am wondering whether i can use sencha touch effects such as animateActiveItem in other framework like bootstrap twitter or zurb foundation.
Thank’s a lot, knowing this is hugely crucial to me smile

Larry

2 years ago

When referencing the Sencha libraries across the web, how do you avoid the “ran insecure content” errors when using Chrome or IE?  Example: “The page at https://*******.na5.visual.force.com/apex/sencha ran insecure content from http://cdn.sencha.io/try/touch/2.0.1/sencha-touch-all.js

Don Robins

2 years ago

Larry: Chrome and IE do not easily allow insecure content. The CDN serving up the Sencha library and CSS is not running https, which is why I suggest in the post to run the app on the desktop using Safari which does allow it. If you prefer not to use Safari, you can download the Sencha Touch library and CSS and upload to your Salesforce.com org as a static resource.  You will then have to set the library links to point to the JS and CSS $Resources that you establish by name, which would look something like this:

[removed][removed]
<link rel=“stylesheet” href=”{!URLFOR($Resource.SenchaTouchCSS_v_2_0_1_1)}” type=“text/css” />

We chose to use the CDN for JS and CSS so that the tutorial could be performed with a minimum of infrastructure configuration. Hope this helps.

Don Robins

2 years ago

Hmm…of course I can’t embed examples of script tags here - so I’ll try again this way:

EMBED IN AN HTML SCRIPT TAG:
script type=“text/javascript” src=”{!$Resource.SenchaTouchAll_v_2_0_1_1}” 

EMBED IN AN HTML LINK TAG:
link rel=“stylesheet” href=”{!URLFOR($Resource.SenchaTouchCSS_v_2_0_1_1)}” type=“text/css” 

Don Robns

2 years ago

@Jihane…I don’t know the answer to your question regarding merging functionality, but suggest you post your question on the Sencha forums where you will get more exposure. You might also post on StackOverflow as there is a sizable Sencha community there as well.

Comments are Gravatar enabled. Your email address will not be shown.

Commenting is not available in this channel entry.