Showing posts with label Salesforce1. Show all posts
Showing posts with label Salesforce1. Show all posts

Monday, April 6, 2015


Salesforce trailhead is here for a while, but I somehow avoided it , but finally decided into jumping into the same. There is whole big list of modules in there but the one that certainly draw me to itself was Visualforce Mobile !




Trailhead really a fun way to learn stuff about platform, and really presents the concepts well.


About the Visualforce Mobile Module


This module takes you from Basic to advanced custom css to suite the look and feel of Salesforce1. It covers all of them !

  • A quick getting started
  • A quick small tour to using Salesforce RemoteObjects in visualforce pages.
  • Using global Actions
  • Talks a lot of bot Salesforce1 design and StyleGuide. Mainly focused about how to make your pages mobile 
  • Also the one-starter library
  • And finally a bit about different JS libraries like AngularJS , Ionic and Bootstrap

Why its important ?


Well trailhead is really well compiled module, and I wish I had covered this a bit before ! I have already covered similar topics in my past but it still looks fresh. At the end of the day on mobile UX does matters. A mobile user definately wants the information to be presented in a well organized manner. Something like




Trailhead was a really fun experience and awesome way to learn the Mobile Visualforce pages ! And hey there are lot many modules in there. Here are the few from my todo list






You can read them all here 

https://developer.salesforce.com/trailhead/modules




Friday, June 13, 2014


Modals are part of the Visualstrap from very beginning but I never talked much about them. Modals can be really help to enhance the user experience. They can let you do many things without going to and fro between pages.

In Salesforce, we are used to this type of arrangement. For example have a look at the "New" / "Edit" buttons, they will take you to a another page to accomplish the task. It feels a bit clunky.
To make the experience  fluid and fast these pages can be replaced with modals.

Scenario 

Lets say we want a page where
  • See all the cases
  • Create new cases
The page can be extended to close and update the cases as well

Prerequisite 

The Page & Controller 

The page and controller are pretty simple.


The Catch

  •  Opening Modal : Modal can be opened using JS or html attribute. In this demo we are using JS
    <a class="btn btn-success btn-md" onclick="$('#newCase').modal('show');return false;">New Case</a> 
    
    
    
Closing the Modal Only when insert is success : We cannot just close the Modal when the user presses the Save button because there can be validation errors/required fields missing etc. To control this we are using a controller variable "isSuccess". We are setting it to true only if the transaction was success and based on the variable value we are calling the modal hide on the page.

Controller : This method sets the isSuccess flag to true only when the records is saved successfully.
    public void saveCase(){
        try{
            insert caseObj;
            init();
            isSuccess = true;
        }
        catch(Exception ex){
            Apexpages.addMessages(ex);
            isSuccess = false;
        }
    }

Page : The below section only renders when isSuccess is true ( and lets the page to close only when the save was success )

<apex:outputPanel rendered="{!isSuccess}">
     <script>
         $('#newCase').modal('hide');
     </script>
</apex:outputPanel>

VSModal in action



Below is the live demo of the page, you are welcome to try creating some cases for me :)

Thursday, March 13, 2014


Salesforce has recently unveiled the new Salesforce1 app that lets you create mobile app very easily using technologies like JS, Visualforce and HTML and yes of course you can use VisualStrap create mobile ready pages.

Since Visualstrap is based on Bootstrap it inherits all the features from Bootstrap. Its a very powerful, sleek, front-end framework that lets you create mobile ready pages very fast!

Creating a Visualforce Page "VSDashboardS1"


So lets start with a User Dashboard / Overview page that we talked earlier here http://blogforce9.blogspot.in/2014/01/visualstrap-possibilities.html

Desktop View

Prerequisite 

Few things that needs to be considered


  • Desktop & Mobile support : Since we are going to support the page both on desktop and mobile we need to find a way to stack the grids on mobile devices so that they can be easily viewed. This can be easily done by using proper grid classes.
  • Navigation : We have to make sure all the links are updated, so that every thing works with Salesforce1 and Desktop
  • Responsive : The page needs to be responsive so that it fits in the screen of different mobile devices.


Desktop & Mobile support 

To make sure the grids properly stack up according to devices we should have to select proper column/ grid classes. In this example we are going to have three blocks per row, since a row in Bootstrap is of 12, each block should span to 4 units, hence the type "col-md-4"

<vs:row>  
   <vs:column type="col-md-4">  
           ...  
   </vs:column>  
   <vs:column type="col-md-4">  
           ...  
   </vs:column>  
   <vs:column type="col-md-4">  
           ...  
   </vs:column>  
 </vs:row>    

col-md-* classes are displayed in single row in a device with regular display where as they get stacked in mobile devices with smaller displays.


Navigation


We have to make sure navigation works for both Salesforce1 and  desktop, this can be done by detecting whether the app is viewed in Salesforce1 or Desktop. Have a look at the below JS function , the function checks whether "sforce.one" exists (which exists for Salesforce1) and switches the navigation method accordingly.

function goToDetailPage(recId){  
       if(typeof sforce != 'undefined' && typeof sforce.one != 'undefined'){  
         sforce.one.navigateToSObject(recId);  
       }  
       else{  
         window.location.href = '/'+recId;  
       }  
       return false;  
     }  


Responsive

Visualstrap grid classes are all responsive and hence they will adapt according to screen width.


The Design

To make sure the page uses all the real estate available on the screen, the page should be stacked vertically for mobile where as it should span horizontally for desktop. This is generally done use grid classes. 

Desktop layout
Mobile Layout


VF Page


 <apex:page sidebar="false" docType="html-5.0" controller="VSDashBoard_Con">  
   <vs:importvisualstrap />  
   <script>  
     function goToDetailPage(recId){  
       if(typeof sforce != 'undefined' && typeof sforce.one != 'undefined'){  
         sforce.one.navigateToSObject(recId);  
       }  
       else{  
         window.location.href = '/'+recId;  
       }  
       return false;  
     }  
   </script>  
   <vs:visualstrapblock style="padding:5px" >  
     <center>   
       <vs:pageheader title="User Dashboard" icon="calendar" subtitle="{!$User.FirstName} {!$User.LastName}"/>   
     </center>  
     <vs:row >  
       <vs:column type="col-md-4">  
         <vs:panel title="Tasks" type="primary">  
           <vs:well style="text-align:center;">  
              <vs:glyph icon="tasks" style="font-size:40px"/> &nbsp;<span style="font-size:54px">{!Tasks.size}</span>  
              <p class="text-muted">Tasks due for Today</p>  
           </vs:well>  
           <apex:dataTable value="{!Tasks}" var="task" styleClass="table table-condensed table-hover table-bordered" rows="3">  
             <apex:column headerValue="Subject">  
               <apex:outputLink onclick="goToDetailPage('{!task.Id}')">{!task.Subject}</apex:outputLink>  
             </apex:column>  
             <apex:column value="{!task.Status}" headerValue="Status"/>  
             <apex:column value="{!task.ActivityDate}" headerValue="Due Date"/>  
           </apex:dataTable>  
           <vs:alert rendered="{!Tasks.empty}" type="success" style="text-align:center">  
             <vs:glyph icon="ok-sign"/> No records to display  
           </vs:alert>  
         </vs:panel>  
       </vs:column>  
       <vs:column type="col-md-4">  
         <vs:panel title="Cases" type="primary">  
           <vs:well style="text-align:center;">  
              <vs:glyph icon="briefcase" style="font-size:40px"/>&nbsp;<span style="font-size:54px">{!Cases.size}</span>  
              <p class="text-muted">Assigned Cases</p>  
           </vs:well>  
           <apex:dataTable value="{!Cases}" var="case" styleClass="table table-condensed table-hover table-bordered" rows="3">  
             <apex:column headerValue="Case Number">  
               <apex:outputLink onclick="return goToDetailPage('{!case.Id}')" >{!case.CaseNumber}</apex:outputLink>  
             </apex:column>  
             <apex:column value="{!case.Status}" headerValue="Status"/>  
             <apex:column value="{!case.Priority}" headerValue="Priority"/>  
           </apex:dataTable>  
           <vs:alert rendered="{!Cases.empty}" type="warning" style="text-align:center">  
             <vs:glyph icon="exclamation-sign"/> No records to display  
           </vs:alert>  
         </vs:panel>  
       </vs:column>  
       <vs:column type="col-md-4">  
         <vs:panel title="Leads" type="primary">  
           <vs:well style="text-align:center;">  
              <vs:glyph icon="user" style="font-size:40px"/>&nbsp;<span style="font-size:54px">{!Leads.size}</span>  
              <p class="text-muted">Unread Leads</p>  
           </vs:well>  
           <apex:dataTable value="{!Leads}" var="lead" styleClass="table table-condensed table-hover table-bordered" rows="3">  
             <apex:column headerValue="Name">  
               <apex:outputLink onclick="return goToDetailPage('{!lead.Id}')" >{!lead.Name}</apex:outputLink>  
             </apex:column>  
             <apex:column value="{!lead.Status}" headerValue="Status"/>  
             <apex:column value="{!lead.CreatedDate}" headerValue="Created Date"/>  
           </apex:dataTable>  
           <vs:alert rendered="{!Leads.empty}" type="warning" style="text-align:center">  
             <vs:glyph icon="exclamation-sign"/> No records to display  
           </vs:alert>  
         </vs:panel>  
       </vs:column>        
     </vs:row>  
     <vs:row >  
       <vs:column type="col-md-6">  
         <vs:panel title="Last Viewed Accounts" type="primary">  
           <apex:dataTable value="{!Accounts}" var="acc" styleClass="table table-condensed table-hover table-bordered" >  
             <apex:column headerValue="Name">  
               <apex:outputLink onclick="return goToDetailPage('{!acc.Id}')" >{!acc.Name}</apex:outputLink>  
             </apex:column>  
             <apex:column value="{!acc.Type}" headerValue="Type"/>  
             <apex:column value="{!acc.BillingState}" headerValue="State"/>  
           </apex:dataTable>  
           <vs:alert rendered="{!Accounts.empty}" type="warning" style="text-align:center">  
             <vs:glyph icon="exclamation-sign"/> No records to display  
           </vs:alert>  
         </vs:panel>  
       </vs:column>  
       <vs:column type="col-md-6">  
         <vs:panel title="Last Viewed Contacts" type="primary">  
           <apex:dataTable value="{!Contacts}" var="contact" styleClass="table table-condensed table-hover table-bordered" rows="3">  
             <apex:column headerValue="Name">  
               <apex:outputLink onclick="return goToDetailPage('{!contact.Id}')" >{!contact.Name}</apex:outputLink>  
             </apex:column>  
             <apex:column value="{!contact.Phone}" headerValue="Phone"/>  
             <apex:column value="{!contact.Department}" headerValue="Department"/>  
           </apex:dataTable>  
           <vs:alert rendered="{!Contacts.empty}" type="warning" style="text-align:center">  
             <vs:glyph icon="exclamation-sign"/> No records to display  
           </vs:alert>  
         </vs:panel>  
       </vs:column>    
     </vs:row>  
   </vs:visualstrapblock>  
 </apex:page>  


Controller


public without sharing class VSDashBoard_Con {  
   public List<Task> getTasks(){  
     return [SELECT Id,Subject,Status, ActivityDate FROM Task WHERE ActivityDate = TODAY AND Status != 'Completed' AND Status != 'Deferred'];  
   }  
   public List<Case> getCases(){  
     return [SELECT Id,CaseNumber,Status,Subject, Priority FROM Case WHERE OwnerId=:UserInfo.getUserId() AND isClosed = FALSE];  
   }  
   public List<Lead> getLeads(){  
     return [SELECT Id,Name,Status, CreatedDate FROM Lead WHERE OwnerId=:UserInfo.getUserId() AND IsUnreadByOwner = true];  
   }  
   public List<Account> getAccounts(){  
     return [SELECT Id,Name,BillingState,Type FROM Account ORDER BY LastViewedDate DESC limit 5 ];  
   }  
   public List<Contact> getContacts(){  
     return [SELECT Id,Name,Phone, Department FROM Contact ORDER BY LastViewedDate DESC limit 5 ];  
   }  
 }  


Deploying the Page to Salesforce1

  • Mark the page VSDashboardS1 "Available for Salesforce mobile apps"

  • Create a Visualforce Tab



  • Add tab to Mobile Navigation Menu




How it looks like on a Mobile Device ?


VSDashboard in the nav menu
The VSDashBoard page
The VSDashBoard page
   
Detail Pages