Friday, 18 September 2015

Pagination using Field Sets (i.e. with customizable columns) - Part # 4

Refer to my previous post on Using Field Sets in Visual force pages


This post explains the pagination in salesforce using field sets which allows easy customization of column display including 
a) what to display
b) what order/sequence

Below markup illustrates this:

Visualforce Page

<apex:page standardController="Product2"  recordsetvar="products" extensions="PaginationTutorial_4">
<apex:pageMessages id="pgm"/>
<apex:form >                     
<apex:pageBlock >
    <apex:outputPanel layout="block" styleClass="pSearchShowMore" id="otpNav2">
        Total Records Found: <apex:outputText rendered="{!IF(Con.resultSize==10000,true,false)}">10000 +</apex:outputText><apex:outputText rendered="{!IF(Con.resultSize < 10000,true,false)}">{!Con.resultSize}</apex:outputText>
        <apex:image url="/img/search_prevarrow_disabled.gif" styleClass="prevArrow" rendered="{!NOT(Con.HasPrevious)}"/>
        <apex:image url="/img/search_prevarrow.gif" title="Previous Page" styleClass="prevArrow" rendered="{!Con.HasPrevious}"/>
        <apex:commandLink action="{!Previous}" title="Previous Page" value="Previous Page" rendered="{!Con.HasPrevious}"/>
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasPrevious)}">Previous Page</apex:outputPanel>         
        &nbsp;({!IF(Con.PageNumber == 1,1,((Con.PageNumber -1) * Con.PageSize)+1)}-{!IF(Con.resultSize < Con.PageSize,Con.resultSize,Con.PageNumber * Con.pageSize)})&nbsp;
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasNext)}">Next Page</apex:outputPanel>         
        <apex:commandLink title="Next Page" value="Next Page" rendered="{!Con.HasNext}" action="{!Next}"/>&nbsp;
        <apex:image url="/img/search_nextarrow.gif" title="Next Page" styleClass="nextArrow" rendered="{!Con.HasNext}"/>
        <apex:image url="/img/search_nextarrow_disabled.gif" rendered="{!NOT(Con.HasNext)}"/>
    </apex:outputPanel>
    <apex:pageBlockTable value="{!products}" var="v">
        <apex:repeat value="{!$ObjectType.Product2.FieldSets.fieldSetForPagination}" var="f">
              <apex:column value="{!v[f.FieldPath]}"/>
        </apex:repeat>      
    </apex:pageBlockTable>
    <apex:outputPanel layout="block" styleClass="pSearchShowMore" id="otpNav">
        Total Records Found: <apex:outputText rendered="{!IF(Con.resultSize==10000,true,false)}">10000 +</apex:outputText><apex:outputText rendered="{!IF(Con.resultSize < 10000,true,false)}">{!Con.resultSize}</apex:outputText>
        <apex:image url="/img/search_prevarrow_disabled.gif" styleClass="prevArrow" rendered="{!NOT(Con.HasPrevious)}"/>
        <apex:image url="/img/search_prevarrow.gif" title="Previous Page" styleClass="prevArrow" rendered="{!Con.HasPrevious}"/>
        <apex:commandLink action="{!Previous}" title="Previous Page" value="Previous Page" rendered="{!Con.HasPrevious}"/>
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasPrevious)}">Previous Page</apex:outputPanel>         
        &nbsp;({!IF(Con.PageNumber == 1,1,((Con.PageNumber -1) * Con.PageSize)+1)}-{!IF(Con.resultSize < Con.PageSize,Con.resultSize,Con.PageNumber * Con.pageSize)})&nbsp;
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasNext)}">Next Page</apex:outputPanel>         
            <apex:commandLink title="Next Page" value="Next Page" rendered="{!Con.HasNext}" action="{!Next}"/>&nbsp;
            <apex:image url="/img/search_nextarrow.gif" title="Next Page" styleClass="nextArrow" rendered="{!Con.HasNext}"/>
            <apex:image url="/img/search_nextarrow_disabled.gif" rendered="{!NOT(Con.HasNext)}"/>          
    </apex:outputPanel>
</apex:pageBlock>
</apex:form>
</apex:page>

Apex Class


public class PaginationTutorial_4
{    
    public ApexPages.StandardSetController con{get; set;}
    public PaginationTutorial_4(ApexPages.StandardSetController controller) 
    {
        con = controller;
        con.setPageSize(10);
    }
      
    //Boolean to check if there are more records after the present displaying records
    public Boolean hasNext
    {
        get
        {
            return con.getHasNext();
        }
        set;
    } 
    //Boolean to check if there are more records before the present displaying records
    public Boolean hasPrevious
    {
        get
        {
            return con.getHasPrevious();
        }
        set;
    } 
    //Page number of the current displaying records
    public Integer pageNumber
    {
        get
        {
            return con.getPageNumber();
        }
        set;
    }
    //Returns the previous page of records
    public void previous()
    {
        con.previous();
    } 
    //Returns the next page of records
    public void next()
    {
        con.next();
    }
}


Field Set


Preview



Advantages

  • Table columns can be customized anytime by adjusting the field set and ends as just a configuration level change
  • We can make any display level changes by directly editing visual force page
  • Both columns and its sequence of display can be controlled
  • Use the dbrequired flag on field set if the pagination is for inline editing

Disadvantages

  • Pagination is limited only to the direct object fields. That is, relationship fields cannot be included. For example, we cannot display Last Modified By user email in this table. We can include this field in the pagination, but this visual force page will fail with exception: System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: LastModifiedBy.Email.
          Hence this pagination is limited only to direct fields for the object in context.
          Further blog posts will cover this exception. Stay tuned.


Tuesday, 15 September 2015

Pagination using Extension controller in addition to the Standard Controller - Part # 3

In this post we are handling the pagination functions via extension controller in addition to the standard controller.

What is Extension Controller?

controller extension is any Apex class containing a constructor that takes a single argument of type ApexPages.StandardController or CustomControllerName , where CustomControllerName is the name of a custom controller you want to extend.

Defining Extension Controller in Visualforce page:
public ApexPages.StandardSetController con{get; set;}
public PaginationTutorial_3(ApexPages.StandardSetController controller) 
{
        this.con = controller;

}


Using Extension Controller in Visualforce page:
<apex:page standardController="Product2"  recordsetvar="products" extensions="PaginationTutorial_3">
.
.
.
.
.
.
</apex:page>


The extension is associated with the page using the extensions attribute of the <apex:page> component.


Defining more than one Extension Controller:

Multiple controller extensions can be defined for a single page through a comma-separated list. This allows for overrides of methods with the same name. For example, if the following page exists:

<apex:page standardController="Account" 
    extensions="ExtOne,ExtTwo" showHeader="false">
    <apex:outputText value="{!foo}" />
</apex:page>
public class ExtOne {
    public ExtOne(ApexPages.StandardController con) { }

    public String getFoo() {
        return 'foo-One';
    }
}

public class ExtTwo {
    public ExtTwo(ApexPages.StandardController con) { }

    public String getFoo() {
        return 'foo-Two';
    }
}

The value of the <apex:outputText> component renders as foo-One. Overrides are defined by whichever methods are defined in the “leftmost” extension, or, the extension that is first in the comma-separated list. Thus, the getFoo method of ExtOne is overriding the method of ExtTwo.

Refer below markup for more details.

Visualforce Page:


<!--
Code Name   : PaginationTutorial_3
Code Type   : Visualforce
Dependency  : PaginationTutorial_3 (Apex Class)
Description : Pagination using Extension controller in addition to the Standard Controller
Author      : Bharathimohan Ramamurthy
-->
<apex:page standardController="Product2"  recordsetvar="products" extensions="PaginationTutorial_3">
<apex:pageMessages id="pgm"/>
<apex:form >                     
<apex:pageBlock >
    <apex:outputPanel layout="block" styleClass="pSearchShowMore" id="otpNav2">
        Total Records Found: <apex:outputText rendered="{!IF(Con.resultSize==10000,true,false)}">10000 +</apex:outputText><apex:outputText rendered="{!IF(Con.resultSize < 10000,true,false)}">{!Con.resultSize}</apex:outputText>
        <apex:image url="/img/search_prevarrow_disabled.gif" styleClass="prevArrow" rendered="{!NOT(Con.HasPrevious)}"/>
        <apex:image url="/img/search_prevarrow.gif" title="Previous Page" styleClass="prevArrow" rendered="{!Con.HasPrevious}"/>
        <apex:commandLink action="{!Previous}" title="Previous Page" value="Previous Page" rendered="{!Con.HasPrevious}"/>
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasPrevious)}">Previous Page</apex:outputPanel>         
        &nbsp;({!IF(Con.PageNumber == 1,1,((Con.PageNumber -1) * Con.PageSize)+1)}-{!IF(Con.resultSize < Con.PageSize,Con.resultSize,Con.PageNumber * Con.pageSize)})&nbsp;
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasNext)}">Next Page</apex:outputPanel>         
        <apex:commandLink title="Next Page" value="Next Page" rendered="{!Con.HasNext}" action="{!Next}"/>&nbsp;
        <apex:image url="/img/search_nextarrow.gif" title="Next Page" styleClass="nextArrow" rendered="{!Con.HasNext}"/>
        <apex:image url="/img/search_nextarrow_disabled.gif" rendered="{!NOT(Con.HasNext)}"/>          
    </apex:outputPanel>            
    <apex:pageBlockTable value="{!products}" var="v">
      <apex:column value="{!v.name}"/>
      <apex:column value="{!v.IsActive}"/>
      <apex:column value="{!v.ProductCode}"/>
      <apex:column value="{!v.RecordTypeId}"/>
      <apex:column value="{!v.CreatedbyId}"/>
      <apex:column value="{!v.CreatedBy.ProfileId}"/>      
      <apex:column value="{!v.CreatedDate}"/>
    </apex:pageBlockTable>
    <apex:outputPanel layout="block" styleClass="pSearchShowMore" id="otpNav">
        Total Records Found: <apex:outputText rendered="{!IF(Con.resultSize==10000,true,false)}">10000 +</apex:outputText><apex:outputText rendered="{!IF(Con.resultSize < 10000,true,false)}">{!Con.resultSize}</apex:outputText>
        <apex:image url="/img/search_prevarrow_disabled.gif" styleClass="prevArrow" rendered="{!NOT(Con.HasPrevious)}"/>
        <apex:image url="/img/search_prevarrow.gif" title="Previous Page" styleClass="prevArrow" rendered="{!Con.HasPrevious}"/>
        <apex:commandLink action="{!Previous}" title="Previous Page" value="Previous Page" rendered="{!Con.HasPrevious}"/>
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasPrevious)}">Previous Page</apex:outputPanel>         
        &nbsp;({!IF(Con.PageNumber == 1,1,((Con.PageNumber -1) * Con.PageSize)+1)}-{!IF(Con.resultSize < Con.PageSize,Con.resultSize,Con.PageNumber * Con.pageSize)})&nbsp;
        <apex:outputPanel styleClass="pShowLess noLink" style="color:grey" rendered="{!NOT(Con.HasNext)}">Next Page</apex:outputPanel>         
            <apex:commandLink title="Next Page" value="Next Page" rendered="{!Con.HasNext}" action="{!Next}"/>&nbsp;
            <apex:image url="/img/search_nextarrow.gif" title="Next Page" styleClass="nextArrow" rendered="{!Con.HasNext}"/>
            <apex:image url="/img/search_nextarrow_disabled.gif" rendered="{!NOT(Con.HasNext)}"/>          
    </apex:outputPanel>
</apex:pageBlock>
</apex:form>
</apex:page>

Extension Controller:


public class PaginationTutorial_3
{    
    public ApexPages.StandardSetController con{get; set;}
    public PaginationTutorial_3(ApexPages.StandardSetController controller) 
    {
        this.con = controller;
        this.con.setPageSize(10);
    }
      
    //Boolean to check if there are more records after the present displaying records
    public Boolean hasNext
    {
        get
        {
            return con.getHasNext();
        }
        set;
    } 
    //Boolean to check if there are more records before the present displaying records
    public Boolean hasPrevious
    {
        get
        {
            return con.getHasPrevious();
        }
        set;
    } 
    //Page number of the current displaying records
    public Integer pageNumber
    {
        get
        {
            return con.getPageNumber();
        }
        set;
    }
    //Returns the previous page of records
    public void previous()
    {
        con.previous();
    } 
    //Returns the next page of records
    public void next()
    {
        con.next();
    }
    
    /*
        
    public List productList
    {
        get
        {
            if(con != null)
                return (List)con.getRecords();
            else
                return null ;
        }
        set;
    } 
    
    */
}


Preview:




Pros:

  • Flexibility in handling pagination via extension controller
  • Compatible design to use Field Sets, especially for Field Sets that include relationship fields (Account.Name on opportunity etc.,). We are discussing this later in another post
  • Ideal design to retrieve and display specific set of records when using SOQL explicitly

Points to Note:

  • Like other Apex classes, controller extensions run in system mode. Consequently, the current user's credentials are not used to execute controller logic, and the user's permissions and field-level security do not apply. However, if a controller extension extends a standard controller, the logic from the standard controller does not execute in system mode. Instead, it executes in user mode, in which the permissions, field-level security, and sharing rules of the current user apply
  • You can choose whether a controller extension respects a user's organization-wide defaults, role hierarchy, and sharing rules by using the with sharing keywords in the class definition

Pagination using List Views with Standard List Controllers - Part # 2

Many Salesforce pages include list views that allow you to filter the records displayed on the page. For example, on the opportunities home page, you can choose to view a list of only the opportunities you own by selecting "My Opportunities" from the list view drop-down.

On a page that is associated with a list controller, you can also use list views.

Standard List Controller Actions:

Action Description
first Displays the first page of records in the set
last Displays the last page of records in the set
next Displays the next page of records in the set
previous Displays the previous page of records in the set


For example, to create a simple list of products (as explained in Tutorial # 1) with a list view, create a page with the following markup:

Visualforce Page

<!--
Code Name   : PaginationTutorial_2
Code Type   : Visualforce
Description : Pagination using List Views with Standard List Controllers
Author      : Bharathimohan Ramamurthy
/-->
<apex:page standardController="Product2" recordSetvar="products">
<apex:form >
<apex:pageBlock title="Pagination using List Views with Standard List Controllers">
    <apex:pageBlockButtons location="top">
        <div style="float:left;font-weight:bold;">
            <apex:outputLabel value="Select View:"/>
            <apex:selectList value="{!filterId}" size="1">
                <apex:actionSupport event="onchange" rerender="myTable"/>
               <apex:selectOptions value="{!listviewoptions}"/>
            </apex:selectList>
        </div>
        <div style="float:center;font-weight:bold;">
            <apex:commandLink action="{!first}">First</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!previous}">Previous</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!next}">Next</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!last}">Last</apex:commandlink> &nbsp;&nbsp;
        </div>
    </apex:pageBlockButtons>
      <apex:pageBlockTable value="{!products}" var="v" id="myTable">
          <apex:column value="{!v.name}"/>
          <apex:column value="{!v.IsActive}"/>
          <apex:column value="{!v.ProductCode}"/>
          <apex:column value="{!v.RecordTypeId}"/>
          <apex:column value="{!v.CreatedbyId}"/>
          <apex:column value="{!v.CreatedBy.ProfileId}"/>      
          <apex:column value="{!v.CreatedDate}"/>
      </apex:pageBlockTable>           
</apex:pageBlock>
</apex:form>
</apex:page>


Preview Screenshot



Points to Note
  • When using a standard list controller, the returned records sort on the first column of data, as defined by the current view, even if that column is not rendered
  • When you use the standardController attribute on the <apex:page> tag, you cannot use the controller attribute at the same time
  • The recordSetVar attribute not only indicates that the page uses a list controller, it indicates the variable name of the record collection. This variable can then be used to access data from the record collection
  • This page does not specify a filter in the request, so the page is displayed is based on the last used filter. To check this behavior, reload your visual force page and go to the Products tab and you can observe that records displayed in first page on both these tables are same
  • Using visualforce expressions, we can access data from the records and embed to the page
  • We can traverse up to five levels of child-to-parent relationships and one level of parent-to-child relationships (Refer to Column "Profile" in screenshot for example)
  • By default, a list controller returns 20 records on the page


Pros
  • No Apex Class required and hence no test class
  • Minimal effort for development
  • No SOQL queries issued to sfdc server
  • Governor limits are not in scope for this page. However the view state limit still applies but will be minimal always as only lesser records are displayed in each page

Cons
  • No more than 10,000 records can be returned by a standard list controller. Custom controllers can work with larger results sets
  • No table sorting on records
  • No Search functionality
  • No customizations to column headers like changing label, css etc.,(Refer to Column "Profile" in screenshot for example, which suppose to be renamed as "Created User Profile" instead for better understanding)
  • You cannot filter records to be displayed inside the table dynamically through code as it was controlled by the list view

Standard List Controller Pagination-Part # 1

This post explains you the first level of pagination in salesforce using Standard list controller.

Standard list controller

Standard list controllers allow you to create Visualforce pages that can display set of records. List views, related lists, mass action pages are examples of existing Salesforce pages that work with a set of records.

Standard list controllers can be used with the following objects:

1. Account
2. Asset
3. Campaign
4. Case
5. Contact
6. Contract
7. Idea
8. Lead
9. Opportunity
10. Order
11. Product2
12. Solution
13. User
14. All Custom objects

Using a standard list controller is very similar to using a standard controller. First you set the standardController attribute on the <apex:page> component, then you set the recordSetVar attribute on the same component.

For example, to associate a page with the standard list controller for products, use the following markup:



<apex:page standardController="Product2" recordSetvar="products">

Accessing data with List Controllers
Once you have associated a page with a list controller, you can refer to the set of records using visualforce expressions. For example, to create a simple table of products, create a page with the following markup:

Visualforce Page : PaginationTutorial_1


<apex:page standardController="Product2" recordSetvar="products">
<apex:form >
<apex:pageBlock title="Product Pagination using Standard List Controller">
    <apex:pageBlockButtons location="bottom">
        <div style="float:center;font-weight:bold;">
            <apex:commandLink action="{!first}">First</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!previous}">Previous</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!next}">Next</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!last}">Last</apex:commandlink> &nbsp;&nbsp;
        </div>
    </apex:pageBlockButtons>
      <apex:pageBlockTable value="{!products}" var="v">
          <apex:column value="{!v.name}"/>
          <apex:column value="{!v.IsActive}"/>
          <apex:column value="{!v.ProductCode}"/>
          <apex:column value="{!v.RecordTypeId}"/>
          <apex:column value="{!v.CreatedbyId}"/>
          <apex:column value="{!v.CreatedBy.ProfileId}"/>      
          <apex:column value="{!v.CreatedDate}"/>
      </apex:pageBlockTable>           
</apex:pageBlock>
</apex:form>
</apex:page>


Preview


Standard List Controller Pagination-Part # 1

Points to Note
  • When you use the standardController attribute on the <apex:page> tag, you cannot use the controller attribute at the same time
  • The recordSetVar attribute not only indicates that the page uses a list controller, it indicates the variable name of the record collection. This variable can then be used to access data from the record collection
  • This page does not specify a filter in the request, so the page is displayed is based on the last used filter. To check this behavior, reload your visual force page and go to the Products tab and you can observe that records displayed in first page on both these tables are same
  • When using a standard list controller, the returned records sort on the first column of data, as defined by the current view, even if that column is not rendered. More details on "Using List Views with Standard List Controllers" was discussed in Pagination using List Views with Standard List Controllers - Part # 2.
  • Using visualforce expressions, we can access data from the records and embed to the page
  • We can traverse up to five levels of child-to-parent relationships and one level of parent-to-child relationships (Refer to Column "Profile" in screenshot for example)
  • By default, a list controller returns 20 records on the page


Pros
  • No Apex Class required and hence no test class
  • Minimal effort for development
  • No SOQL queries issued to sfdc server (at-least explicitly)
  • Governor limits are not in scope for this page. However the view state limit and heap size limit still applies but will be minimal always as only lesser records are displayed in each page

Cons
  • No more than 10,000 records can be returned by a standard list controller. Custom controllers can work with larger results sets
  • No table sorting on records
  • No Search functionality
  • No customizations to column headers like changing label, css etc.,(Refer to Column "Profile" in screenshot for example, which suppose to be renamed as "Created User Profile" instead for better understanding)
  • You cannot filter records to be displayed inside the table dynamically through code as it was controlled by the list view



Salesforce Pagination Methods, Procedures, Pros and Cons of each

What is Pagination in Salesforce?

Pagination in Salesforce is a process of dividing large amount of records from Salesforce database into multiple pages with each page at a predefined records size and presenting it to user in a page by page display. User will navigate through the pages using the navigation buttons.

What is Salesforce List Views?


Salesforce allows to create list views to see a specific set of records of all Standard Objects and all custom objects provided if objects are/can be exposed via custom tab.
For Example,
Standard Objects: Opportunity, Contacts, Accounts etc.,
Custom Objects: All (if you expose via custom tabs)

The list view criteria can be modified using the filter criteria and filter expressions. Access to these list views can be controlled by sharing the view to specific group of users or to all users. In addition, each user can also create and have their individual view not shared to others.


However, the standard list views cannot be used for most of our customization's in Visual force (refer next section).


What makes Pagination in Salesforce Important?


Standard salesforce list view pagination cannot be used in the following few scenarios,

    - Display all records chatter followed by myself in a table

    - Display all Opportunities that has a specific Product in its line item list
    - Display a specific set of records (based on criteria), that will allow user to select individual records and to some further processing/action
    - Display records in a table and allow user to change filter criteria dynamically

Hence visual force custom pagination becomes essential


Why Pagination in Salesforce is difficult?


Implementing custom pagination on a visual force is certainly not easy and it comes through practice. Developer has to win all the below limits when building pagination in order to make a successful pagination design.

Governor Limits:
Total number of records retrieved by SOQL queries

Total number of records retrieved by Database.getQueryLocator
Total heap size
Maximum CPU time on the Salesforce servers
Maximum execution time for each Apex transaction

Other Limits:
StandardSetController restrictions/limits
OFFSET limits

What are the various pagination methods/design available in salesforce?


Visualforce StandardSetController
The query and queryMore Force.com SOAP API Calls
OFFSET Clauses within SOQL Queries
Your custom logic for pagination

What is a ideal pagination design?


As such there is nothing called ideal pagination in salesforce. It depends on the actual requirement and to decide on which pagination to select.

What we are going to learn?


Further posts will explain you on all possible paginations along with actual code with screenshots. We will discuss both server side pagination and client side pagination in next posts.

Using Field Sets in Visual force pages

Field Sets in Visualforce?

Field Set in salesforce is a grouping of fields that can be used by developers to build custom visual force pages to display the fields and data using visualforce binding expressions. Administrators can later add or remove fields from the field set and the visualforce page will reflect to these changes.

Benefits?

1. By making visualforce page to use field set, we can avoid recurring changes/enhancements to the same component again and again when a field has to be added or removed
2. Free from migrations, test class coverage as no changes at component level is required
3. Component becomes dynamic
4. By passing the field set name dynamically through code, we can make the same visual force page to use different field set displaying different set of fields based on any criteria/logic
5. As field set allows selection of relationship fields and visualpage displays the same
6. Helps managed package users/subscribing orgs to use managed package field sets and let them to customize managed package VF pages to customize (only if their vendor built pages using field sets)

Below markup explains the use of Field Sets in visual force page:

Visualforce page


<!-- 
Code Name : VisualforceUsingFieldSet
Code Type  : Visualforce
Description : Using Field Set in Visualforce page
Author        : Bharathimohan Ramamurthy
/-->
<apex:page standardController="Product2" recordSetvar="products">
<apex:form >
<apex:pageBlock title="Using Field Sets in Visualforce Page">
    <apex:pageBlockButtons location="top">
        <div style="float:left;font-weight:bold;">
            <apex:outputLabel value="Select View:"/>
            <apex:selectList value="{!filterId}" size="1">
                <apex:actionSupport event="onchange" rerender="myTable"/>
               <apex:selectOptions value="{!listviewoptions}"/>
            </apex:selectList>
        </div>
        <div style="float:center;font-weight:bold;">
            <apex:commandLink action="{!first}">First</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!previous}">Previous</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!next}">Next</apex:commandlink> &nbsp;&nbsp;
            <apex:commandLink action="{!last}">Last</apex:commandlink> &nbsp;&nbsp;
        </div>
    </apex:pageBlockButtons>
      <apex:pageBlockTable value="{!products}" var="v" id="myTable">
          <apex:repeat value="{!$ObjectType.Product2.FieldSets.fieldSetForPagination}" var="f">
              <apex:column value="{!v[f.FieldPath]}"/>
        </apex:repeat>
      </apex:pageBlockTable>           
</apex:pageBlock>
</apex:form>
</apex:page>


Preview


Using Field Sets in Visual force pages


{!$ObjectType.Product2.FieldSets.fieldSetForPagination}

$ObjectType - Global Variable
Product2 - Object API Name
FieldSets - Keyword (use as such)
fieldSetForPagination - Your field set api name goes here. To access managed package field sets, use namespace as prefix with ( __ ) in between.

Considerations

1. Field will be required if visual force page is in edit mode and if the field set field is marked as required (DB required attribute determines this)
2. Maximum number of field sets that can be referenced in a page is 50 (..way beyond than ideal need for anyone)

Saturday, 22 August 2015

Simple Contact Search using Angular JS + Bootstrap

This post explains you a basic use of Angular JS + Salesforce Remote Objects + Bootstrap Css.

app.js

var myapp = angular.module("myAngularMVC",[]);
myapp.controller("myAngularMVCController",function($scope)
{
 
 $scope.fetch = function(contactName)
 { 
     var wh = new SObjectModel.contact();
     
     wh.retrieve({where: {Name: {eq: contactName }}}, function(err, records, event)
     {
         if(err) 
         {
             alert(err.message);
         }
         else 
         {
             var ul = document.getElementById("contactsList");
             ul.innerHTML = '';
             records.forEach(function(record) 
             {
                 var whText = record.get("Name");
                 whText += " -- ";
                 whText += record.get("Phone");
                 
                 var li = document.createElement("li");
                 li.appendChild(document.createTextNode(whText));
                 ul.appendChild(li);
             });
         }
     });
 };
});

Visualforce Page

<apex:page>
<script src="{!URLFOR($Resource.angulardemo,'vendor/angular.min.js')}"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>
<script src="{!URLFOR($Resource.angulardemo,'app/app.js')}"/>

<div ng-app="myAngularMVC">
    <apex:remoteobjects>
        <apex:remoteobjectmodel fields="Id,Name" jsshorthand="contact" name="Contact">
            <apex:remoteobjectfield jsshorthand="phone" name="Phone"/>
        </apex:remoteobjectmodel>
    </apex:remoteobjects>

    <div ng-controller="myAngularMVCController">
        <form class="form-inline">
            <div class="form-group">
            <label for="exampleInputName2">Contact Name</label>
               <input class="form-control" ng-model="contactName" placeholder="Enter Name to search" type="text"/>
            </div>
            <button class="btn btn-default" ng-click="fetch(contactName)" type="submit">Search</button>    
            <ul id="contactsList"></ul>
        </form>
    </div>
</div>
</apex:page>

Preview

Saturday, 16 May 2015

Login As another User from Sidebar link - For System Administrators and Developers

Whenever we do some customization or VF page development for a specific profile users, there will be a need to test the development by logging in with that profile.

By doing so, we can track or identify the issues making our development totally error free.

To do this, we need to search for a user and click "Login" button on user detail page every time assuming if the access is already granted or if the setting Administrators Can Log in as Any User is enabled.

This post guides you an easiest way of handling the process, by logging in as another user directly from the sidebar link and if the access is granted.



Create a Custom Link by following the below path,

Your Name ➤ App Setup ➤ Home ➤ Custom Links ➤ New

Label : Contract Operations

Name : Contract_Operations
Behaviour : Execute Javascript

Paste the below code,



{!REQUIRESCRIPT("/soap/ajax/18.0/connection.js")}
sforce.connection.query("SELECT Id,Name,Profile.Name FROM User where Profile.Name=\'Contract Operations\' LIMIT 1",{onSuccess: handleSuccess,onFailure: handleFailure});

function handleSuccess(queryresult)
{
    try
    {
        records = queryresult.getArray("records");
        var user = sforce.connection.getUserInfo();
        window.location.href = '/servlet/servlet.su oid='+user.organizationId+'&suorgadminid='+records[0].Id.substring(0,15)+
'&retURL=%2Fhome%2Fhome.jsp'+'&targetURL=%2Fhome%2Fhome.jsp';
    }
    catch(error)
    {
        alert(error);
    }
}
function handleFailure(error)
{
    alert(error);
}

You can have as may have links created for different profiles also.

Create a Custom Component using below path,


Your Name ➤ App Setup ➤ Home ➤ Home Page Components ➤ New


Name : Login As.....

Type  :  Links

- Include the Custom Link that was created previously.

- Finally include this Custom Component in the System Administrator Home Page Layout under Narrow(Left) column.

Wednesday, 13 May 2015

Basic Search Page using Angular JS

This post explains using of Visualforce Remote Objects with Angular JS.

Salesforce explanation on Visualforce Remote Objects:

"JavaScript remoting is a popular, powerful, and efficient method for building Web apps with Visualforce, especially for creating pages for use in Salesforce1 or working with JavaScript libraries such as jQuery or AngularJS. Visualforce Remote Objects are proxy objects that enable basic DML operations on sObjects directly from JavaScript. Remote Objects remove some of the complexity from JavaScript remoting by reducing the need for @RemoteAction methods in an Apex controller or extension.

Behind the scenes, the Remote Objects controller handles sharing rules, field level security, and other data accessibility concerns. Pages that use Remote Objects are subject to all the standard Visualforce limits, but like JavaScript remoting, Remote Objects calls don’t count toward API request limits. Using Visualforce Remote Objects consists of implementing two separate pieces of functionality on the same page.

Access definitions, written in Visualforce with the Remote Objects components. These components generate a set of JavaScript proxy objects that you can use in step 2.

Data access functions, written in JavaScript. These functions use the proxy objects that are made available by the access definitions to perform create, retrieve, update, and delete operations on your data.

Your page then uses the data access functions to respond to user interaction, such as form submissions or controls changes, or to perform periodic actions in response to timers, or most anything that you can write in JavaScript."

Please read Visualforce Remote Objects article for more details.

Visualforce Page : AngularMVC


<apex:page >
<script src="{!URLFOR($Resource.angulardemo,'jssrc/angular.min.js')}"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"/>
<script src="{!URLFOR($Resource.angulardemo,'app/app.js')}"></script>
<div ng-app="myAngularMVC">
    <apex:remoteObjects >
        <apex:remoteObjectModel name="Contact" jsShorthand="contact" fields="Id,Name">
            <apex:remoteObjectField name="Phone" jsShorthand="phone"/>
        </apex:remoteObjectModel>
    </apex:remoteObjects>    
    <div ng-controller="myAngularMVCController">
        <input type="text" name="txtSearch" class="form-control" placeholder="Enter Name to search" ng-model="contactName"/>           
        <button type="button" class="btn btn-default" ng-click="fetch(contactName)">Search</button>
        <table class="table table-striped table-hover table-bordered">
        <thead>
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>Phone</th>             
            </tr>
        </thead>
        <tfoot>
        </tfoot>
        <tbody>
            <tr ng-repeat="contact in contactList">
                <td>
                    {{contact.id}}
                </td>
                <td>
                    {{contact.Name}}
                </td>
                <td>
                    {{contact.Phone}}
                </td>
            </tr>
        </tbody>
    </table>
    </div>
</div>   
</apex:page>

app.js


var myapp = angular.module("myAngularMVC",[]);
myapp.controller("myAngularMVCController",function($scope)
{ 
 $scope.contactList = [];
 $scope.fetch = function(contactName)
 { 
     var wh = new SObjectModel.contact();     
     wh.retrieve({where: {Name: {eq: contactName }}}, function(err, records, event)
     {
         if(err) 
         {
             alert(err.message);
         }
         else 
         {
          $scope.contactList=[];            
             records.forEach(function(record) 
             {              
              $scope.contactList.push(ContactWrapper.contact(record));
             });
             $scope.$apply();
         }
     });
 };
});
var ContactWrapper = function() 
{

};

ContactWrapper.contact = function(model) 
{
 var wrap = new ContactWrapper();
 wrap.id = model.get('Id');
 wrap.Name = model.get('Name');
 wrap.Phone = model.get('Phone');
 return wrap;
}


Preview



Static Resource Structure



Running your first Angular App in Salesforce

This post explains you a simple HelloWorld program in Salesforce using AngularJS

Visualforce page:



 
 
 
{{message}}

Angular Basics to start with...in Salesforce

This post expalins few basic angular directives and binding concepts to start with. Use contact id in the URL. For example,

https://c.na24.visual.force.com/apex/AngularBasics?Id=0031a000001YveQ

Visualforce Page: AngularBasics
<apex:page applybodytag="false" doctype="html-5.0" showheader="false" standardstylesheets="false" standardController="Contact">
<!--
applybodytag[DEFAULT this to false]: 
A Boolean value that specifies whether or not Visualforce should automatically add a <body> tag to the generated HTML output. Set to false to disable adding the <body> tag to the response.
For example, when the <body> tag is statically set in your markup. If not specified, this value defaults to the value of the applyHtmlTag attribute if it's set, or true, if applyHtmlTag isn't set.

applyHtmlTag:
A Boolean value that specifies whether or not Visualforce should automatically add an <html> tag to the generated HTML output. 
Set to false to disable adding the <html> tag to the response, for example, when the <html> tag is statically set in your markup. If not specified, this value defaults to true.

doctype[DEFAULT this to html-5.0]:
The HTML document type definition (DTD), or doctype, that describes the structure of the rendered page. If not specified, this value defaults to "html-4.01-transitional", which results in a doctype of . 
Possible values for this attribute include "html-4.01-strict", "xhtml-1.0-transitional", "xhtml-1.1-basic", and "html-5.0", among others.

showheader[DEFAULT this to false]:
A Boolean value that specifies whether the Salesforce tab header is included in the page. If true, the tab header is displayed. If not specified, this value defaults to true.

standardStylesheets[DEFAULT this to false]:
A Boolean value that specifies whether the standard Salesforce stylesheets are added to the generated page header if the showHeader attribute is set to false.
If set to true, the standard stylesheets are added to the generated page header. If not specified, this value defaults to true.
By setting this to false, components that require Salesforce.com CSS may not display correctly, and their styling may change between releases.
/-->

<!-- Include Angular SRC using direct script tag or using apex:component -->
<script src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>

<script>
    <!-- Defining angular app here. App is named as AngularBasicsApp -->    
    var app = angular.module("AngularBasicsApp",[]);
    <!-- Defining angular controller here. Controller is named as AngularBasicsController taking $scope as parameter -->
    app.controller("AngularBasicsController",function($scope)
    {
        <!-- attach helloworldmessage to scope -->
        $scope.helloworldmessage = "Hello! This is my first angular app..."
        $scope.contactname = "{!Contact.Name}";
        $scope.email = "{!contact.email}";
        $scope.imgurl = "{!Contact.PhotoUrl}";
        $scope.phonedetails = function(){
                                  var phone = "Phone: {!Contact.Phone}";
                                  var otherphone = "OtherPhone:{!Contact.OtherPhone}";
                                  return phone+"-----"+otherphone;
                              }
        $scope.printfunction = function(testinput){
                                   return testinput; 
                               }
    });
</script>
<div ng-app="AngularBasicsApp" ng-init="contactid='{!Contact.Id}'">
    <div ng-controller="AngularBasicsController">
        <fieldset>
            <legend>Binding using braces:</legend>
                <!-- Angular Binding using double braces  -->
                <h4>{{helloworldmessage}}</h4>            
        </fieldset>
        
        <fieldset>
            <legend>Binding using ng-bind directive:</legend>
            <!-- Angular Binding using ng-bind directive  -->
            <h4 ng-bind="helloworldmessage"></h4>
        </fieldset>
        
        <fieldset>
            <legend>SFDC Contact Name:</legend>        
            <span><image ng-src="{{imgurl}}"/></span>
            <span ng-bind="contactname"></span><br/>
            <span ng-bind="email"></span>
        </fieldset>
        
        <fieldset>
            <legend>Sample Input and Output Text Display</legend>
            <p>
                <input type="text" ng-model="myinputtext"/>
                <span ng-bind="myinputtext"></span>            
            </p>
        </fieldset>
        
        <fieldset>
            <legend>Simple Maths</legend>
            <p>
                {{500/21}}           
            </p>
        </fieldset>    
        
        <fieldset>
            <legend>Simple Maths using dynamic input</legend>
            <p>Enter Distance: <input type="text" ng-model="distance"/></p>
            <p>Enter Time: <input type="text" ng-model="time"/></p>
            <p>Velocity Is: {{distance/time}}</p>
        </fieldset>    
        
        <fieldset>
            <legend>Contact ID display using ng-init</legend>
            <p>
                {{contactid}}           
            </p>
        </fieldset>  
        
        <fieldset>
            <legend>Binding output of a function</legend>
            <p>
                {{phonedetails()}}           
            </p>
        </fieldset>
        
        <fieldset>
            <legend>Passing parameter to a function and binding the output</legend>
            <p>
                {{printfunction("Sample Print")}}           
            </p>
        </fieldset>
        
        <fieldset>
            <legend>ng-disabled</legend>
            <p>
                <button ng-disabled="switch">UnCheck to enable me</button>
                <input type="checkbox" ng-model="switch" ng-init="switch=true"/>
            </p>
        </fieldset>
        
        <fieldset>
            <legend>ng-show</legend>
            <p>
                <button ng-show="switchVisibility">UnCheck to Hide Me!</button>
                <input type="checkbox" ng-model="switchVisibility" ng-init="switchVisibility=true"/>
            </p>
        </fieldset>
        
        <fieldset>
            <legend>ng-hide</legend>
            <p>
                <button ng-hide="hideMe">Check to Hide Me!</button>
                <input type="checkbox" ng-model="hideMe" ng-init="hideMe=false"/>
            </p>
        </fieldset>
              
    </div>
</div>
</apex:page>
Preview:




Sunday, 22 March 2015

Accessing Report data using "Salesforce1 Reporting API via Apex"

This post explains you a basic code structure for fetching data from an existing report and display it in visualforce page.

Report Screenshot





Visualforce Page Screenshot


Visualforce Page

<apex:page controller="OpportunityReportUsingAnalyticsAPI" readOnly="true">
<apex:pageMessages/>
<apex:form> 
  <apex:outputPanel id="reportResults" layout="block" style="overflow: auto;width:100%;height:435px;">
    <apex:outputText value="Fetching results. Please wait!" rendered="{!IsReportRunning}"/>
    <apex:pageBlock rendered="{!NOT(IsReportRunning)}" title="Opportunity Report.....">
    <table style="width: 100%;">
        <thead>
            <apex:variable value="1" var="count"/>
            <apex:repeat value="{!reportResults.reportMetadata.detailColumns}" var="colName">
            <th><apex:outputText value="{!reportResults.reportExtendedMetadata.detailColumnInfo[colName].label}"/></th>
            </apex:repeat>
        </thead>
        <tbody>
                <apex:repeat value="{!reportResults.factMap['T!T'].rows}" var="row">
                <tr>
                    <apex:repeat value="{!row.dataCells}" var="cell">                           
                        <td><apex:outputText value="{!cell.label}"/></td>
                    </apex:repeat>
                </tr>
                </apex:repeat>
        </tbody>
    </table>
    </apex:pageBlock>
  </apex:outputPanel>
<apex:actionPoller id="poller" reRender="reportResults" interval="5" action="{!checkReportRunningStatus}" enabled="{!IsReportRunning}" />
</apex:form>
</apex:page>


Apex Controller

public with sharing class OpportunityReportUsingAnalyticsAPI
{
    // get reportId from URL
    public Id reportId=ApexPages.currentPage().getParameters().get('reportId');
    public Id instanceId { get; set; }
   
    //flag to indicate whether report is still running or not
    public Boolean IsReportRunning { get; set; }
   
    // stores reportresults
    private transient Reports.ReportResults reportResults;         
   
    // constructor
    public OpportunityReportUsingAnalyticsAPI()
    {                  
        if(reportId!=null)
        {            
            Reports.ReportInstance reportInstance = Reports.ReportManager.runAsyncReport(reportId,true);
            instanceId = reportInstance.getId();
            checkReportRunningStatus();
        }
        else
        {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL,'Invalid URL, reportId is missing'));
        }
    }
   
    // method to get and populate reportresults
    public PageReference checkReportRunningStatus()
    {
        Reports.ReportInstance reportInstance = Reports.ReportManager.getReportInstance(instanceId);     
        IsReportRunning = reportInstance.getStatus() == 'Running' || reportInstance.getStatus() == 'New';
        if (!IsReportRunning)
        {
            reportResults = reportInstance.getReportResults();
        }       
        return null;
    }

    // returns reportresults
    public Reports.ReportResults getReportResults()
    {
        return reportResults;
    }

}

This code structure remains the same for any apex implementing this API like filtering report dynamically based on filters applied in visual force page.