SlideShare a Scribd company logo
Force.com Webinar:
                                       Advanced Visualforce

                                       Eric Wilson
                                       Director, Product Management
                                       UI Platforms




Join the conversation: #forcewebinar
Agenda
      1. Assumptions
      2. Your Frienemy: View State
      3. Managing View State
      4. Asynchronous Apex




Join the conversation: #forcewebinar
Assumptions




Join the conversation: #forcewebinar
This Advanced Webinar Assumes...


      ...you have used Visualforce and are comfortable with it.


      ...you have used Apex and are comfortable writing it.


      ...you understand HTML, JavaScript, and AJAX concepts.




Join the conversation: #forcewebinar
Your Frienemy:
                                         View State




Join the conversation: #forcewebinar
Q: What is View State?
      A: An encrypted, hidden <input> field on a Visualforce page that
      keeps track of Apex controller state & Visualforce page state
      between server requests. This field is only generated when
      there is an <apex:form> tag present on a page.




Join the conversation: #forcewebinar
Visualforce Lifecycle
   A


                                                HTTP GET

                                                           A. URL Requested
                               E                           B. Apex Controller Instantiated on Server
                           HTTP POST
                                                           C. Controller State Serialized & Encrypted to View State

                                                           D. Page Markup Sent to Browser & Rendered
    D
                                                     B     E. View State Decrypted & Deserialized (for Postbacks)




           <input type="hidden" value="..."/>    C


Join the conversation: #forcewebinar
View State: Your Frienemy



                   Why it’s Great :-)               Why it’s Not So Great :-(
      • Automatically keeps track of field    • Can be bulky, affecting performance.
        values for you.                       • It has size limitations.
      • Allows for easy AJAX functionality.   • Doesn’t allow for complex AJAX
      • Provides easy way to re-render page    functionality.
        components.




Join the conversation: #forcewebinar
View State is Required for...
   <apex:action*>
   <apex:command*>
   <apex:inlineEditSupport>
   <apex:input*>
   <apex:select*>




Join the conversation: #forcewebinar
Managing View State




Join the conversation: #forcewebinar
How Can I Manage My View State?
   A. Reduce Number of Components
   B. Use the transient Keyword
   C. Use JavaScript Remoting
   D. Use the Streaming API




Join the conversation: #forcewebinar
Option A: Reduce Number of Components

          <apex:outputPanel layout="inline"...>   <span...>


          <apex:outputPanel layout="block"...>    <div...>


          <apex:panelGrid...>                     <table...>


          <apex:outputLink...>                    <a...>


          <apex:outputText styleClass="..."...>   <span...>




Join the conversation: #forcewebinar
Option B: Use the transient Keyword


      public with sharing class EditClientController {

      	           public               Contact         client              {   get;   set;   }
      	 transient public               List<Contact>   connections         {   get;   set;   }
      	 transient public               List<Account>   previousEmployers   {   get;   set;   }
      	 transient public               Set<String>     hashTags            {   get;   set;   }

            ...

      }




Join the conversation: #forcewebinar
Option B: Use the transient Keyword

             BEFORE
             AFTER




                                         58%




Join the conversation: #forcewebinar
Option C: Use JavaScript Remoting
   Q: What is JavaScript Remoting?
   A: Stateless way to call Apex controller methods from JavaScript.




Join the conversation: #forcewebinar
Option C: Use JavaScript Remoting



                            Find Customer:




                                       <apex:actionFunction ... />
                                        <apex:actionRegion ... />
                                            JavaScript Remoting
                                       <apex:actionSupport ... />




Join the conversation: #forcewebinar
JavaScript Remoting Lifecycle




                                       JS Function

                                       Apex Method
                                                     Client-side

                                       JS Callback   Server-side




Join the conversation: #forcewebinar
JS Function


                                       Apex Method


                                       JS Callback




Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The Page

 <apex:page controller="FindCustomerController">

        <input id="searchField" type="text" placeholder="Enter Last Name"/>
        <button onclick="handleButtonClick();">Search</button>

        <table>
            <tbody id="results"></tbody>
        </table>
                                                                      JS Function

 </apex:page>                                                         Apex Method


                                                                      JS Callback




Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The Page

 <apex:page controller="FindCustomerController">

        <input id="searchField" type="text" placeholder="Enter Last Name"/>
        <button onclick="handleButtonClick();">Search</button>

        <table>
            <tbody id="results"></tbody>
        </table>
                                                                      JS Function

 </apex:page>                                                         Apex Method


                                                                      JS Callback




Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The JavaScript




     function handleButtonClick() {
         var searchTerm = document.getElementById("searchField").value;
         FindCustomerController.doSearch(searchTerm, renderResults);
     }

                                                                    JS Function


                                                                    Apex Method


                                                                    JS Callback




Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The JavaScript




     function handleButtonClick() {
         var searchTerm = document.getElementById("searchField").value;
         FindCustomerController.doSearch(searchTerm, renderResults);
     }
                           Apex Class   Apex Method   Apex Method Parameter   JS Callback Function


                                                                                                     JS Function


                                                                                                     Apex Method


                                                                                                     JS Callback




Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The Apex Class
     public with sharing class FindCustomerController {

           @RemoteAction
           public static List<Contact> doSearch(String customerLastName) {
               customerLastName = '%' + customerLastName + '%';
               return [
                   SELECT id, FirstName, LastName
                   FROM Contact
                   WHERE LastName LIKE :customerLastName
                   LIMIT 200
               ];                                                      JS Function

           }                                                           Apex Method


                                                                            JS Callback
     }


Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The Apex Class
     public with sharing class FindCustomerController {

           @RemoteAction
           public static List<Contact> doSearch(String customerLastName) {
               customerLastName = '%' + customerLastName + '%';
               return [
                   SELECT id, FirstName, LastName
                   FROM Contact
                   WHERE LastName LIKE :customerLastName
                   LIMIT 200
               ];                                                      JS Function

           }                                                           Apex Method


                                                                            JS Callback
     }


Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The Callback


   function renderResults(results, event) {
       var container = document.getElementById("results"),
                html = [];
       for (var i=0, j=results.length; i<j; i++) {
           html.push("<tr><td>");
           html.push(results[i].LastName + ", " + results[i].FirstName);
           html.push("</td></tr>");
       }
       container.innerHTML = html.join("");                         JS Function

   }                                                                Apex Method


                                                                         JS Callback




Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The Results




                                                JS Function


                                                Apex Method


                                                JS Callback




Join the conversation: #forcewebinar
Option C: JavaScript Remoting: The Results




          BEFORE                                AFTER
           234ms                                152ms
                                                 35%




Join the conversation: #forcewebinar
Option D: Use the Streaming API
   Q: What is the Streaming API?
   A: A highly performant way to get near-real-time updates from
      a Salesforce instance without polling.




Join the conversation: #forcewebinar
Option D: Use the Streaming API
    BEFORE
<apex:page controller="NewAccountsController">
<apex:form>

     <apex:actionPoller action="{!find}" rerender="wrapper" interval="15"/>
     <h1>Streaming API Example</h1>
     <h2>New Accounts</h2>
     <apex:outputPanel id="wrapper"></apex:outputPanel>

</apex:form>
</apex:page>




Join the conversation: #forcewebinar
Option D: Use the Streaming API
    AFTER
<apex:page controller="NewAccountsController">

     <apex:includeScript value="..."/> <!-- 4 js files needed -->

     <h1>Streaming API Example</h1>
     <h2>New Accounts</h2>
     <div id="wrapper"></div>
     <script>... $.cometd.init(...) $.cometd.subscribe(...) ...</script>

</apex:page>




Join the conversation: #forcewebinar
Option D: Use the Streaming API: Steps
   Determine Your SOQL Query
   Create a PushTopic Record
   Include Necessary JavaScript Libraries on Visualforce Page
   Call cometd’s init(...) and subscribe(...) Functions (Inline JS)
   Watch Magic Happen




Join the conversation: #forcewebinar
Asynchronous Apex




Join the conversation: #forcewebinar
Asynchronous Apex
       public with sharing class SendInvoiceController{

             @RemoteAction
             public static String requestAllInvoices(String customerId) {
                 sendAllInvoices(customerId);
                 return('All invoices have been requested.');
             }

             @future
             private static void sendAllInvoices(String customerId) {
                 EmailHelper.emailCustomerInvoices(customerId);
             }

       }


Join the conversation: #forcewebinar
Survey
          Your feedback is crucial to the success of our webinar programs.
                                        Thank you!

                   http://bit.ly/advancedvfsurvey




Join the conversation: #forcewebinar
Q&A

                                       Eric Wilson
                                       Director, Product Management
                                       UI Platforms




Join the conversation: #forcewebinar
Upcoming Events

                     December 11, 2012
                     AppExchange for Developers Webinar
                     http://bit.ly/XnFERP


                     December 12, 2012
                     Apex CodeTalk Live Q&A
                     http://bit.ly/apexct-vf

  Check out the Developer Force calendar for upcoming local events such as meetups,
  workshops, and user group meetings: http://developer.force.com/Calendar


Join the conversation: #forcewebinar

More Related Content

PDF
EVOLVE'14 | Enhance | Gabriel Walt | Sightly Component Development
PPTX
Taking Apex and Visualforce Above and Beyond
PDF
Securing JSF Applications Against the OWASP Top Ten
PDF
Spring 3 - Der dritte Frühling
PDF
In The Brain of Cagatay Civici: Exploring JavaServer Faces 2.0 and PrimeFaces
PDF
JavaFX – 10 things I love about you
PDF
JavaServer Faces 2.0 - JavaOne India 2011
PDF
Spring 3 - An Introduction
EVOLVE'14 | Enhance | Gabriel Walt | Sightly Component Development
Taking Apex and Visualforce Above and Beyond
Securing JSF Applications Against the OWASP Top Ten
Spring 3 - Der dritte Frühling
In The Brain of Cagatay Civici: Exploring JavaServer Faces 2.0 and PrimeFaces
JavaFX – 10 things I love about you
JavaServer Faces 2.0 - JavaOne India 2011
Spring 3 - An Introduction

What's hot (20)

PDF
What You Need To Build Cool Enterprise Applications With JSF
PDF
Webtests Reloaded - Webtest with Selenium, TestNG, Groovy and Maven
PDF
When Smalltalk Meets the Web
PDF
Visualforce: Using ActionFunction vs. RemoteAction
PDF
PrimeTime JSF with PrimeFaces - Dec 2014
PPTX
Sightly - Part 2
PDF
PDF
Primefaces Confess 2012
PDF
Boston 2011 OTN Developer Days - Java EE 6
PPT
Visualforce: Using JavaScript Remoting for Apex Controllers
PDF
OSDC 2009 Rails Turtorial
PDF
IBM WebSphere Portal Integrator for SAP - Escenario de ejemplo.
PDF
Difference between-action-support
PDF
Stripes Framework
PPTX
Introduction to Plugin Programming, WordCamp Miami 2011
PDF
CakePHP
PDF
Real use cases of performance optimization in magento 2
PDF
Java Web Development with Stripes
PDF
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
PDF
Alfresco Tech Talk Live-Web Editor - 3.3
What You Need To Build Cool Enterprise Applications With JSF
Webtests Reloaded - Webtest with Selenium, TestNG, Groovy and Maven
When Smalltalk Meets the Web
Visualforce: Using ActionFunction vs. RemoteAction
PrimeTime JSF with PrimeFaces - Dec 2014
Sightly - Part 2
Primefaces Confess 2012
Boston 2011 OTN Developer Days - Java EE 6
Visualforce: Using JavaScript Remoting for Apex Controllers
OSDC 2009 Rails Turtorial
IBM WebSphere Portal Integrator for SAP - Escenario de ejemplo.
Difference between-action-support
Stripes Framework
Introduction to Plugin Programming, WordCamp Miami 2011
CakePHP
Real use cases of performance optimization in magento 2
Java Web Development with Stripes
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
Alfresco Tech Talk Live-Web Editor - 3.3
Ad

Similar to Advanced Visualforce Webinar (20)

PPTX
Uniface Lectures Webinar - Building Responsive Applications with Uniface: Dev...
PPTX
How to perform debounce in react
PPT
Asp.Net Ajax Component Development
PDF
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
PDF
RichFaces: rich:* component library
PDF
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
PPTX
PDF
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
PDF
AnkaraJUG Kasım 2012 - PrimeFaces
PDF
Comet from JavaOne 2008
PDF
What's new in Rails 5 - API Mode & Action Cable overview
PDF
Ajax Under The Hood
PDF
From Backbone to Ember and Back(bone) Again
PPTX
Behavioral pattern 4
PDF
Introduction to RichFaces
KEY
Javascript Frameworks for Well Architected, Immersive Web Apps
PPT
JSF Component Behaviors
PDF
Integrating React.js Into a PHP Application
PDF
JSF 2.0 Preview
KEY
Modular Web Applications With Netzke
Uniface Lectures Webinar - Building Responsive Applications with Uniface: Dev...
How to perform debounce in react
Asp.Net Ajax Component Development
Spark IT 2011 - Simplified Web Development using Java Server Faces 2.0
RichFaces: rich:* component library
Hyperproductive JSF 2.0 @ JavaOne Brazil 2010
L2 Web App Development Guest Lecture At University of Surrey 20/11/09
AnkaraJUG Kasım 2012 - PrimeFaces
Comet from JavaOne 2008
What's new in Rails 5 - API Mode & Action Cable overview
Ajax Under The Hood
From Backbone to Ember and Back(bone) Again
Behavioral pattern 4
Introduction to RichFaces
Javascript Frameworks for Well Architected, Immersive Web Apps
JSF Component Behaviors
Integrating React.js Into a PHP Application
JSF 2.0 Preview
Modular Web Applications With Netzke
Ad

More from Salesforce Developers (20)

PDF
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
PDF
Maximizing Salesforce Lightning Experience and Lightning Component Performance
PDF
Local development with Open Source Base Components
PPTX
TrailheaDX India : Developer Highlights
PDF
Why developers shouldn’t miss TrailheaDX India
PPTX
CodeLive: Build Lightning Web Components faster with Local Development
PPTX
CodeLive: Converting Aura Components to Lightning Web Components
PPTX
Enterprise-grade UI with open source Lightning Web Components
PPTX
TrailheaDX and Summer '19: Developer Highlights
PDF
Live coding with LWC
PDF
Lightning web components - Episode 4 : Security and Testing
PDF
LWC Episode 3- Component Communication and Aura Interoperability
PDF
Lightning web components episode 2- work with salesforce data
PDF
Lightning web components - Episode 1 - An Introduction
PDF
Migrating CPQ to Advanced Calculator and JSQCP
PDF
Scale with Large Data Volumes and Big Objects in Salesforce
PDF
Replicate Salesforce Data in Real Time with Change Data Capture
PDF
Modern Development with Salesforce DX
PDF
Get Into Lightning Flow Development
PDF
Integrate CMS Content Into Lightning Communities with CMS Connect
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Local development with Open Source Base Components
TrailheaDX India : Developer Highlights
Why developers shouldn’t miss TrailheaDX India
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Converting Aura Components to Lightning Web Components
Enterprise-grade UI with open source Lightning Web Components
TrailheaDX and Summer '19: Developer Highlights
Live coding with LWC
Lightning web components - Episode 4 : Security and Testing
LWC Episode 3- Component Communication and Aura Interoperability
Lightning web components episode 2- work with salesforce data
Lightning web components - Episode 1 - An Introduction
Migrating CPQ to Advanced Calculator and JSQCP
Scale with Large Data Volumes and Big Objects in Salesforce
Replicate Salesforce Data in Real Time with Change Data Capture
Modern Development with Salesforce DX
Get Into Lightning Flow Development
Integrate CMS Content Into Lightning Communities with CMS Connect

Advanced Visualforce Webinar

  • 1. Force.com Webinar: Advanced Visualforce Eric Wilson Director, Product Management UI Platforms Join the conversation: #forcewebinar
  • 2. Agenda 1. Assumptions 2. Your Frienemy: View State 3. Managing View State 4. Asynchronous Apex Join the conversation: #forcewebinar
  • 4. This Advanced Webinar Assumes... ...you have used Visualforce and are comfortable with it. ...you have used Apex and are comfortable writing it. ...you understand HTML, JavaScript, and AJAX concepts. Join the conversation: #forcewebinar
  • 5. Your Frienemy: View State Join the conversation: #forcewebinar
  • 6. Q: What is View State? A: An encrypted, hidden <input> field on a Visualforce page that keeps track of Apex controller state & Visualforce page state between server requests. This field is only generated when there is an <apex:form> tag present on a page. Join the conversation: #forcewebinar
  • 7. Visualforce Lifecycle A HTTP GET A. URL Requested E B. Apex Controller Instantiated on Server HTTP POST C. Controller State Serialized & Encrypted to View State D. Page Markup Sent to Browser & Rendered D B E. View State Decrypted & Deserialized (for Postbacks) <input type="hidden" value="..."/> C Join the conversation: #forcewebinar
  • 8. View State: Your Frienemy Why it’s Great :-) Why it’s Not So Great :-( • Automatically keeps track of field • Can be bulky, affecting performance. values for you. • It has size limitations. • Allows for easy AJAX functionality. • Doesn’t allow for complex AJAX • Provides easy way to re-render page functionality. components. Join the conversation: #forcewebinar
  • 9. View State is Required for... <apex:action*> <apex:command*> <apex:inlineEditSupport> <apex:input*> <apex:select*> Join the conversation: #forcewebinar
  • 10. Managing View State Join the conversation: #forcewebinar
  • 11. How Can I Manage My View State? A. Reduce Number of Components B. Use the transient Keyword C. Use JavaScript Remoting D. Use the Streaming API Join the conversation: #forcewebinar
  • 12. Option A: Reduce Number of Components <apex:outputPanel layout="inline"...> <span...> <apex:outputPanel layout="block"...> <div...> <apex:panelGrid...> <table...> <apex:outputLink...> <a...> <apex:outputText styleClass="..."...> <span...> Join the conversation: #forcewebinar
  • 13. Option B: Use the transient Keyword public with sharing class EditClientController { public Contact client { get; set; } transient public List<Contact> connections { get; set; } transient public List<Account> previousEmployers { get; set; } transient public Set<String> hashTags { get; set; } ... } Join the conversation: #forcewebinar
  • 14. Option B: Use the transient Keyword BEFORE AFTER 58% Join the conversation: #forcewebinar
  • 15. Option C: Use JavaScript Remoting Q: What is JavaScript Remoting? A: Stateless way to call Apex controller methods from JavaScript. Join the conversation: #forcewebinar
  • 16. Option C: Use JavaScript Remoting Find Customer: <apex:actionFunction ... /> <apex:actionRegion ... /> JavaScript Remoting <apex:actionSupport ... /> Join the conversation: #forcewebinar
  • 17. JavaScript Remoting Lifecycle JS Function Apex Method Client-side JS Callback Server-side Join the conversation: #forcewebinar
  • 18. JS Function Apex Method JS Callback Join the conversation: #forcewebinar
  • 19. Option C: JavaScript Remoting: The Page <apex:page controller="FindCustomerController"> <input id="searchField" type="text" placeholder="Enter Last Name"/> <button onclick="handleButtonClick();">Search</button> <table> <tbody id="results"></tbody> </table> JS Function </apex:page> Apex Method JS Callback Join the conversation: #forcewebinar
  • 20. Option C: JavaScript Remoting: The Page <apex:page controller="FindCustomerController"> <input id="searchField" type="text" placeholder="Enter Last Name"/> <button onclick="handleButtonClick();">Search</button> <table> <tbody id="results"></tbody> </table> JS Function </apex:page> Apex Method JS Callback Join the conversation: #forcewebinar
  • 21. Option C: JavaScript Remoting: The JavaScript function handleButtonClick() { var searchTerm = document.getElementById("searchField").value; FindCustomerController.doSearch(searchTerm, renderResults); } JS Function Apex Method JS Callback Join the conversation: #forcewebinar
  • 22. Option C: JavaScript Remoting: The JavaScript function handleButtonClick() { var searchTerm = document.getElementById("searchField").value; FindCustomerController.doSearch(searchTerm, renderResults); } Apex Class Apex Method Apex Method Parameter JS Callback Function JS Function Apex Method JS Callback Join the conversation: #forcewebinar
  • 23. Option C: JavaScript Remoting: The Apex Class public with sharing class FindCustomerController { @RemoteAction public static List<Contact> doSearch(String customerLastName) { customerLastName = '%' + customerLastName + '%'; return [ SELECT id, FirstName, LastName FROM Contact WHERE LastName LIKE :customerLastName LIMIT 200 ]; JS Function } Apex Method JS Callback } Join the conversation: #forcewebinar
  • 24. Option C: JavaScript Remoting: The Apex Class public with sharing class FindCustomerController { @RemoteAction public static List<Contact> doSearch(String customerLastName) { customerLastName = '%' + customerLastName + '%'; return [ SELECT id, FirstName, LastName FROM Contact WHERE LastName LIKE :customerLastName LIMIT 200 ]; JS Function } Apex Method JS Callback } Join the conversation: #forcewebinar
  • 25. Option C: JavaScript Remoting: The Callback function renderResults(results, event) { var container = document.getElementById("results"), html = []; for (var i=0, j=results.length; i<j; i++) { html.push("<tr><td>"); html.push(results[i].LastName + ", " + results[i].FirstName); html.push("</td></tr>"); } container.innerHTML = html.join(""); JS Function } Apex Method JS Callback Join the conversation: #forcewebinar
  • 26. Option C: JavaScript Remoting: The Results JS Function Apex Method JS Callback Join the conversation: #forcewebinar
  • 27. Option C: JavaScript Remoting: The Results BEFORE AFTER 234ms 152ms 35% Join the conversation: #forcewebinar
  • 28. Option D: Use the Streaming API Q: What is the Streaming API? A: A highly performant way to get near-real-time updates from a Salesforce instance without polling. Join the conversation: #forcewebinar
  • 29. Option D: Use the Streaming API BEFORE <apex:page controller="NewAccountsController"> <apex:form> <apex:actionPoller action="{!find}" rerender="wrapper" interval="15"/> <h1>Streaming API Example</h1> <h2>New Accounts</h2> <apex:outputPanel id="wrapper"></apex:outputPanel> </apex:form> </apex:page> Join the conversation: #forcewebinar
  • 30. Option D: Use the Streaming API AFTER <apex:page controller="NewAccountsController"> <apex:includeScript value="..."/> <!-- 4 js files needed --> <h1>Streaming API Example</h1> <h2>New Accounts</h2> <div id="wrapper"></div> <script>... $.cometd.init(...) $.cometd.subscribe(...) ...</script> </apex:page> Join the conversation: #forcewebinar
  • 31. Option D: Use the Streaming API: Steps Determine Your SOQL Query Create a PushTopic Record Include Necessary JavaScript Libraries on Visualforce Page Call cometd’s init(...) and subscribe(...) Functions (Inline JS) Watch Magic Happen Join the conversation: #forcewebinar
  • 32. Asynchronous Apex Join the conversation: #forcewebinar
  • 33. Asynchronous Apex public with sharing class SendInvoiceController{ @RemoteAction public static String requestAllInvoices(String customerId) { sendAllInvoices(customerId); return('All invoices have been requested.'); } @future private static void sendAllInvoices(String customerId) { EmailHelper.emailCustomerInvoices(customerId); } } Join the conversation: #forcewebinar
  • 34. Survey Your feedback is crucial to the success of our webinar programs. Thank you! http://bit.ly/advancedvfsurvey Join the conversation: #forcewebinar
  • 35. Q&A Eric Wilson Director, Product Management UI Platforms Join the conversation: #forcewebinar
  • 36. Upcoming Events December 11, 2012 AppExchange for Developers Webinar http://bit.ly/XnFERP December 12, 2012 Apex CodeTalk Live Q&A http://bit.ly/apexct-vf Check out the Developer Force calendar for upcoming local events such as meetups, workshops, and user group meetings: http://developer.force.com/Calendar Join the conversation: #forcewebinar