Saturday, December 14, 2013


After around months of playing with Bootstrap and Visualforce here is a first version of "VisualStrap". VisualStrap is a set of components that work inside your visualforce page without affecting the standard layouts (if you directly import Bootstrap inside a VF page it will mess up the whole page).

With VisualStrap you can make your VF pages more appealing to user , more responsive and more user friendly. Currently the below set components are Bootstrap are converted into VisualStrap but I am working hard to bring them all.

What you get with this version of VisualStrap ?  

  • Panels
  • Alert
  • Well
  • Label
  • Badges
  • Jumbotron
  • Forms (Vertical and Horizontal)
  • Glyphicons
  • Thumbnails
  • Column and Rows (Grid) 
  • Tables (new 1.1)
  • Buttons (new 1.1)
  • ButtonGroup (new in v1.3)
  • ButtonToolBar (new in v1.3
  • Pageheader (new in v1.3)
  • Progressbar (new in v1.3)
  • Tooltip (new in v1.4)
  • List Group and List Group Item (new in v1.4)
  • Modal (new in v1.4)
  • Navbar (new in v1.4)
 VisualStrap is  available as a managed package so that it will be easy for users to upgrade it whenever a new release is released (Source is available @Github please check the project detail page) 







Where can you use it ?

Almost everywhere! But you can consider VisualStrap for pages that are exposed as Salesforce Sites or in Customer Portal. 

To get started and create some awesome UI  please follow the project link below

Documentation & Installation 

Please visit the Project page for documentation, Installation and Github link.

Tuesday, December 3, 2013


Well I have been working on VF pages for a long time now and I use a lot of AJAX / Rerender. Generally user has to wait for a AJAX action to complete to get results. So how to show the user something is working in background ? a wait screen ?

Yes indeed a wait screen with "Please Wait..." is required. I have already done some demos about the same here Loading/Wait Screen Using Jquery.

But that requires a bit of coding.
  • Add JS functions and ActionStatus
  • You may have to change your existing code to accommodate actionStatus
  • Add the new code and upload everything in static resource
Well to summarize if you need to show a generic message for all the AJAX calls that is talking place from the page you have to make changes to all the Action component to include a action status. So that raises a question can we built a listener that can track a AJAX call. The answer is yes we can build one. VFUIBlock does uses a generic listener to track the AJAX calls. 

Whats special about "VFUIBlock" ?

Its a generic componet that hooks up to all the AJAX calls and listens to them. You just have to install the component and drop the component in a Visualforce Page. It will automatically attaches itself to all the AJAX request originating from the page and will show a wait screen while the request is in Progress. No need to make any changes in your existing code, No need to use any actionstatus, It does it all by itself!

VFUIBlock in Action

How it works ?
In Visualforce AJAX request are sent to server using XMLHttpRequest, So what VFUIBlock does is, it overrides the default XMLHttpRequest and plugs in its own onSend method and OnReadyStateChange method while preserving the old Send and OnReadyStateChange method. Now with this override VFUIBlock adds in its on method with some extra fancy stuff to Show a block screen.

/*THIS IS A JUST A PORTION OF CODE, PLEASE VISIT PROJECT DETAIL FOR FULL SOURCE CODE*/
function addXMLRequestCallback($) {  
   var oldSend, i, oldonreadystatechange;  
   /*hold the old send method*/  
   oldSend = XMLHttpRequest.prototype.send;  
   /*override with a new function*/  
   XMLHttpRequest.prototype.send = function () {  
     /*call the blockui function or any other custom function to show your message*/  
     onStart($);  
     /*call the old send method*/  
     oldSend.apply(this, arguments);  
     /*cache the old onreadystate change method*/  
     oldonreadystatechange = this.onreadystatechange;  
     this.onreadystatechange = function (progress) {  
       oldonreadystatechange(progress);  
       /*call the blockui function or any other custom function to hide the message*/  
       onStop($);  
     };  
   }  
 }  



VFUIBlock uses the good old jQueryUIBlock to create the wait screen. Its a jQuery plugin which is used to create a overlay and to show a message to the user.


Features
  • Lets you customise the HTML that is being displayed to user
  • Automatically attaches itself to AJAX events events originated from CommandButton,CommandLink etc.
  • No coding and changes in existing code required.
  • Works with CommandButton , ActionFunciton, ActionPoller, ActionSupport.
Sample Code / Syntax

Just drop the below code somewhere in your page

<c:VFBlockUI>  
   <img src="/img/loading32.gif" />  
   <div style="font-size:150%;padding:5px">Please Wait....</div>  
</c:VFBlockUI>

You can always customise your message. So anything wrapped inside this VF component is displayed to User. In this example we are displaying a standard "Loading" image a long with a text "Please Wait..."


Friday, November 29, 2013


Well few days back got a requirement for creating a History reporting app, which can run reports on History Object based on Date and User. My first reaction was, "Force.com supports reporting on History Object and we don't need a app here". But after reading the docs found that there were limitations


  • You cannot run report on a object which a child (in master detail relation)
  • And the number of records that were displayed, I had a requirement to show around 20k records

Well now it was pretty clear that I need to develop a app that can do reporting on these child objects, but that was not so complex. Most challenging part of the requirement was to display 20k records. When playing with that many records on a VF page we generally have to think about
  • View State :  we cannot go beyond 132Kb, I was sure with 20k records I am going to hit the limits
  • Script Limit : There is a limit on how may script we can run. And since the data from History table will require some transformation(User Name mapping,Date formatting,Field Api to Field Label etc), I was lil sceptical that I am going to hit the limits .
  • Pagination :  We cannot just show that many records on a single page!
  • A way to implement Search , Filtering and Sorting : without sorting and search user will be almost lost !

So finally after weeks of work, A app that can show around whooping 40K records! and that too with Export, Sorting and Pagination (Filters are in for the next version).

Fetching Data




History Reporting App





Well this app shows the limit to which we can take a simple VF app. This is not limited to only History Objects, we can extend this to any Object with custom filters as per need. Currently the app is in Beta version, there are some bugs specially related to Case History, Activity History.


Thursday, November 28, 2013


On my quest to create a perfect PageBlockTable, I tried a lot of jQuery plugin available out there. The main moto was to bring as many as feature I can. Some of them were good but were almost dead and were at end of their lifetime. Others were not compatible with Visualforce, some were not able to pick the standard pageblock table and other had css issues. Finally after long search I stopped on two plugins

  • TableSorter
     Description : tablesorter is a jQuery plugin for turning a standard HTML table with THEAD and TBODY tags into a sortable table without page refreshes. tablesorter can successfully parse and sort many types of data including linked data in a cell.

    I find it very interesting because its very minimal and doesn't changes the DOM much and easily attaches itself VF Pageblocktable. All the version of PageblockTableEnhancer uses this to add Sorting and Pagination capability to a standard VF Pageblocktable. The combination really went well and I guess many of out there are using it now. This plugin is still actively developed and well be enhanced further but I don't think there is much scope to bring new features because its architecture is bit limiting
  • Datatables
    Description : DataTables is a plug-in for the jQuery Javascript library. It is a highly flexible tool, based upon the foundations of progressive enhancement, which will add advanced interaction controls to any HTML table


    Datatable - looks futuristics isn't it ?


    Well Datatables ! everybody out there working on Dynamic Tables can't stop talking about it because of the amazing flexibilty and combination of features this gives. Features like Sorting,Pagination,Search can easily be implemented on very large table just using this table. And there is no boundaries support PDF/CSV export has been recently added and everyday some new plugin is introduced. Its the plugin of the future! Its still actively developed, there are lot of user already using this, new features are added and I see a lot of scope here!

So whats new ? 

I have been trying to combine Datatables with Standard VF Pageblock table. But somehow wasn't able to make them work together. But finally I was able to combine them and result is just awesome looking new table!.  Yes I was successfully able to combine them and create a new component called PageblocktableEnhancerADV(adv for Advanced, lol I know that sounds a bit funny ) .

I kept both of the plugin alive because people can choose from which one they want. If you like the Default look and feel you can go with PageblockTableEnhancer  else you can use the new PageblocktableEnhancerADV.

Personally I feel like there is lot of scope in PageblocktableEnhancerADV, since its based on Datatables there is lot scope and there is a long list feature waiting to be ported.

So Introducing the "PageblocktableEnhancerADV" with the backbone of "PageblocktableEnhancer", same ease of use, same set of parameters, just one line and  you are ready to rock!

Detail about the PageBlockTableEnhancerADV Component
(If you are using the PageblocktableEnhancer you should be aware about the basic parameters)

Here is what is new with this plugin
  1. Pagination Support.
  2. Support for specifying available page sizes.
  3. Support for choosing default page size on page load.
  4. Dynamic Search/filter
  5. No Coding and Changes Required in existing code.
  6. Hassle free installation

List o Parameters
  • targetPbTableIds : comma-separated Ids of the target Pageblock tables
  • paginate : Assign true if you want to use the pagination feature,default value is true.
  • pageSizeOptions : A comma seperated list of integer values that will displayed as dropdown for page size
  • defaultPageSize : Default page size that needs to be selected (at page load).
Ajax/Rerender support
  • This version brings in support for rendering, the earlier version wasn't able to handle this. So incase you are rerendering your table or the parent components, you can call the "initPageBlockTableEnhancerADV()" method from "oncomplete" even of your commandButtons/actionFunctions/actionSupport/commandLink .

    <apex:commandButton value="Rerender" reRender="mid" oncomplete="initPageBlockTableEnhancerADV()"/>
Basic Syntax
The basic syntax remains same, just few added params.

<c:PageBlockTableEnhancerADV targetPbTableIds="mid,mid2" paginate="true" defaultPageSize="5" pageSizeOptions="5,10,20,30,40,50,100"/>    
   <apex:pageBlock >   
     <apex:pageBlockTable value="{!contacts}" var="con" id="mid">   
      <apex:column value="{!con.Name}"/>   
     </apex:pageBlockTable>    
     <apex:pageBlockTable value="{!contacts}" var="con" id="mid2">   
      <apex:column value="{!con.Name}"/>   
     </apex:pageBlockTable>     
   </apex:pageBlock>  
PageBlockTableEnhacerADV - Optimized version of Datatable for VF




Future Enhancements

  • Export to CSV and PDF
  • Copy to clipboard
  • Print

Saturday, October 26, 2013


Well this is very early release, was a bit excited when I found that it actually works! and I couldn't wait to till completion of app. So I just created a bare minimum version of this component to Post the same.

Well talking about the component it is pretty simple and uses  JSZip (can be found here) to create zip files inside a Visualforce page. I will be posting the  details about how VFZip actually works in subsequent blogs.
For now I am just posting a small unmanaged package that can create Zip files, I will be working on this further to expand the same.

Features of VFZip
  • Can zip multiple files.
  • You can provide your own name for the generated zip files.
  • Can zip upto 5mb(I know its kinda discouraging but I guess I can take it further around 15mb)

How to use ?
The syntax is pretty simple 


<c:VFZip attachmentIds="00P90000004wnj8" generatedFileName="myzip" mode="button"/>  

[Please make sure you replace the id with one from your org]

Parameters
  • attachmentIds : Comma separated IDs of attachment to zip
  • generatedFileName : File name of the generated zip.
  • mode : Defines the launch mode. If set to "button" the component will display a button to launch the zip window. If set to "auto" the component will launch the zip window as soon as Visualforce page is opened.
Screens




Friday, October 11, 2013


Well I know this is nothing new, I just wanted to jot it down quickly!

Force.com supports triggers @Attachments but as of now you can't create them from standard UI, but hey wait we can create them with the NEW Developer Console. Yes the Developer console(v29.0) is more like Eclipse now and allows you to create a triggers on Attachments.

So here is how you can create a trigger @ Attachment



  • Click at your Name(left top corner) and Select "Developer Console"

    Developer Console Selection

  • Now when you are inside Developer Console . Go to File >>  New >> Apex Trigger

    New Apex Trigger
  • Select "Attachment" in sObject and and give a good Name to your trigger.  

Thats it ! you are ready to go!.

Sample Attachment Trigger


Description : Say you want to create a trigger on Attachment which will update a custom field "Last_Attachment_Added_Date__c" on "Account" with the date when the Last Attachment was added.

Prerequisite : "Last_Attachment_Added_Date__c" custom  Date/Time field on Account Standard Object.


 trigger AttachmentTrigger on Attachment (before insert) {  
   Boolean isAccountAttachment = FALSE;    
      List<Account> accounts = new List<Account>();  
        Set<Id> accIds = new Set<Id>();  
        for(Attachment att : trigger.New){  
             /*Check if uploaded attachment is related to Account Attachment and same account is already added*/  
             if(att.ParentId.getSobjectType() == Account.SobjectType && (!accIds.contains(att.ParentId)){  
                  //prepare a account object for update  
                  accounts.add(  
                                      new Account(  
                                                          Id=:att.ParentId,  
                                                          Last_Attachment_Added_Date__c = System.today()  
                                                        )  
                                    );  
                     //add the accountid in set to eliminate dupe updates                                     
                  accIds.add(att.ParentId);  
             }  
        }  
        //finally update accounts  
        update accounts;  
 }  

The trigger is pretty simple and the trick is in detecting on which object the attachment is being added.

In the above code we are comparing "SobjectType" of the ParentId(for attachment which is added to account SobjectType will be same as of Account Object) and the "Account" to check whether the attachment is added to account.

By using the above code as base you can do many more things like rolling up number of Attachments to its parent object, Some custom validation using trigger on attachment etc.


Sunday, October 6, 2013



Well this one of the most required iteration of my Visualforce Autocomplete Component, which worked well with small data set but starts showing sluggishness with large number of records. After doing some debugging and I felt like the underlying architecture is the problem and needs to be rewritten. And finally while searching for a good JQuery component I came across the Select2 project which looked promising but was a lil but different and was more to do with Picklists. Hmm well gradually I started going deeper into the API and guess what ? I found a way to make it to a Autocomplete component!.

The newer component looked pretty much good and was way faster than the earlier Jquery Autocomplete that I used in V1.

AutocompleteV2 in Action


Summing up few features of the V2

  • The component now uses Select2 instead of Jquery Autocomplete
  • Much more faster than earlier version and can handle large dataset
  • Complete new UI
  • The component no more depends on the Jquery from the package and can use jquery from Visualforce page(if already referred in page).
  •  Configurable : The search field can be configured to search fields other than "Name" field. Even the value that is returned to controller can be configured return fields other than record Id.
How to Use ?

<c:AutoCompleteV2 allowClear="true" importJquery="true" labelField="Name" SObject="Account" valueField="Id" targetField="{!targetField}" style="width:200px"/>  

Description
  • labelField : The field which is displayed in the component  and against which matching is done with the entered text. In above code snippet Name is displayed in the autocomplete component.
  • valueField : The field value which is passed back to targetfield when a record is selected.
  • targetField : The field from controller where the selected values is set.
  • SObject : The sobject Api Name against which matching/query is done.
  • importJquery : Assign false if you dont want to jquery files from package.
  • syncManualEntry : Allow manual entry of data from autocomplete component. So if a matching value is not found for the entered query string, on page submit the same value will be sibmitted to targefield
  • allowClear : Set true to give user a option to clear existing value. If this value is set true user will see a small cross Icon to clear the existing value from the field
In addition to this a Visualforce Page "AutocompleteV2Demo" is included in package. This page searches through different accounts that are available in the Org. Have a look at the same for syntax and implementation



Screens

   


Where can this be used ?
  • It can be used for replacing Lookups and Master Detail fields. Instead of pressing the lookup button user can directly type in the autocomplete field to search and link the right record.
  • It can not only refer Lookups and Master Details but also can search through any object. It can be used as replacement for picklist. Create a object to store the Values available in picklist and use the V2 component to refer the same.(Recommended only when you have large number picklist values to show)
  • Can be used in quick search pages to search for records and swiftly navigate to the record once user submits

Thursday, September 12, 2013


Well finally with time I am learning a thing or two about creating apps. Yes apps, I always tried to build some apps that can be used by different developers/ clients. Although todays topic "MapMyObject" was never going to be app, it was just an experiment to create a reusable component to integrate Google Maps with Force.com and guess what ? the initial results were awesome!. This inspired me a lot to convert this one into a app that can pull Geolocation Data(lat/lang) from any Sobject into a Google maps, where you can visualize them, edit them and even create new records.

Today I am releasing a beta version of this "MapMyObject" which can be installed in a DE org or in a sandbox.

Some of the features

  • Visualize data from any Sobject into a Google Map
  • Edit records from Map
  • Create new records from Map
  • Highly configurable : You can select permission based on Config/Custom Settings, whether a particulat map will allow editing, creation of new record or view existing records.
  • Uses Google Maps API V3
Some Screens
Showing Records

Create New Record

Update Records


Well there are lot more possibilities with this app/component like dashboards, demographics,  Data distribution map.  Well that was lot of bragging about the app! to install the same and to know more about the app please follow the below link : 

Tuesday, September 10, 2013


So here we go, a Visualforce component to show the images from attachment as a slider . This Slider "VFAttachmentSlider" can be used in a inline VF pages and as well as on standalone pages to render a beautiful image slider by pulling images from attachment of a record

VF Attachment Slider


The component uses FlexiGrid2 and jQuery to render the slider, which  itself is very easy to implement. This component "VFAttachmentSlider" goes one step further and makes displaying images from attachment super easy. It pulls all the related attachment of the passed record and queues them into a slider.


Features

  • Easy Syntax : Just pass the Id of the parent record containing the images in attachments to the component and guess what you have a awesome looking Slider.

    Example :
      <c:VFAttachmentSlider recordId="a0190000006ppB5"/>
    *replace the harcoded Id with a merge field or an Id.
  • Prev & Next : Has easy navigation support for previous and next.
  • Pagination : Shows the current page.
  • Responsive Design :  This is something which is also inherited from Flexslider. The image slider automatically adjust according to the size of the images.

Some Examples

  • Using VFAttachmentSlider in inline Page 
    • Account Inline Page :
       <apex:page sidebar="false" standardController="Account">  
         <c:VFAttachmentSlider recordId="{!Account.Id}"/>    
       </apex:page>  
    • Similarly for Contact
       <apex:page sidebar="false" standardController="Contact">  
         <c:VFAttachmentSlider recordId="{!Contact.Id}"/>    
       </apex:page>  
    • Similarly you can use the slider for any Custom Object
       <apex:page sidebar="false" standardController="MyCustomObject__c">  
         <c:VFAttachmentSlider recordId="{!MyCustomObject.Id}"/>    
       </apex:page>  

Sunday, September 1, 2013



Salesforce Rest Services are a powerful as well as convenient way to expose web services from a organization. It uses simple HTTP methods like GET , POST etc. to access and manipulate data. The data exchange format is in the form of JSON generally. 

The following is a sample apex class which illustrates the POST method to post details and GET method to retrieve details from an outside application.


Sample Rest Apex Class:


/*  
   The urlMapping acts as an accessible endpoint and adds to the full URL used to call this webservice from an external point  
   For example, something like "https://ap1.salesforce.com/services/apexrest/Account"  
 */  
 @RestResource(urlMapping='/Account/*')  
 global with sharing class callAccount {  
  /*  
   HttpPost method is used to capture a HttpPost request has been sent to our rest apex class.  
   Used to retrieve data coming in the request body and performing corressponding actions  
  */  
  @HttpPost  
   global static String doPost() {  
     /*  
       RestContext Class - Allows us to access the RestRequest and RestResponse objects in your Apex REST methods.   
       RestRequest class - Allows us to pass request data into our Apex RESTful Web service method.  
       RestResponse class - Allows us to pass or send back response data from our Apex RESTful web service method  
     */  
     //Returns the RestRequest object for our Apex REST method.  
     RestRequest request = RestContext.request;  
     //Returns the RestResponse for our Apex REST method.  
     RestResponse response = RestContext.response;  
     //Access the request body with input data coming in the JSON format  
     String jSONRequestBody=request.requestBody.toString().trim();  
     //Deserializes the input JSON string into an Account object  
     Account accObj = (Account)JSON.deserializeStrict(jSONRequestBody,Account.class);  
     //insert the account object and return the account ID   
     insert accObj;  
     return accObj.Id;  
   }  
   /*  
   HttpGet method is used to capture a HttpGet request has been sent to our rest apex class.  
   Used to request data on the basis of a parameter sent in the URL  
  */  
  @HttpGet  
   global static Account doGet() {  
   /*  
       RestContext Class - Allows us to access the RestRequest and RestResponse objects in your Apex REST methods.   
       RestRequest class - Allows us to pass request data into our Apex RESTful Web service method.  
       RestReponse class - Allows us to pass or send back response data from our Apex RESTful web service method  
     */  
     //Returns the RestRequest object for our Apex REST method.  
     RestRequest request = RestContext.request;  
     //Returns the RestResponse for our Apex REST method.  
     RestResponse response = RestContext.response;  
     //Retrieve the parameter sent in the URL  
     String accountId = request.requestURI.substring(request.requestURI.lastIndexOf('/')+1);  
     //query the account on the basis of id sent and return the record  
     Account acc= [SELECT Id, Name, Phone, Website FROM Account WHERE Id = :accountId];  
     return acc;  
   }  
 }  


Call the Rest  WebService
Set up in salesforce org
1.        Go to Setup, click Create | Apps, and in the Connected Apps section, click New to create a new Connected App.

2.        Enter a Connected App name.
3.        Enter the contact email, as well as any other information appropriate to your application.
4.        Under Section ‘OAuth Settings’, mark the enable OAuth Settings checkbox and enter a Callback URL for example:  https://ap1.salesforce.com/services/oauth2/token



5.        Enter an OAuth scope. Select :




a.        Perform requests on your behalf at any time (refresh_token)
b.        Provide access to your data via the Web (web)
c.        Access and manage your data (API)
6.        Click Save. The Consumer Key is created and displayed, and a Consumer Secret is created (click the link to reveal it).


Call webservice using cURL

To call the rest apex class from outside salesforce, we either need to set up cURL or a client/system capable of making http request. Here is an example showing how to use cURL to call the REST service. 

FIRST we need to download the curl executable file (SSL enabled), preferably from http://curl.haxx.se/download.html (corresponding to the OS and the version) . cURL has some user friendly commands to call the rest service with OAuth authentication.

1.       Command to receive the authorization token :


 curl --form client_id=[Your client Id] --form client_secret=[Your client secret] --form grant_type=password --form username=[Your Username] --form password=[Your Password+Your Security Token] -k https://[Your salesforce instance].salesforce.com/services/oauth2/token  

For example :
curl --form client_id=3MVG9_7ddP9KqTzd_3A4dh9sZ4fpxuyOxHUCQ.GRu6EY7ETY2xFAGBrkv8BO17HmOR_X47cahreAbO7WjQgLd --form client_secret=2607521253690956513 --form grant_type=password --form username=test@gmail.com --form password=password1$RjzaF3v6HahniNEWpxUlUIoG -k https://cs10.salesforce.com/services/oauth2/token  


2.        Use cURL to call the webservice
a.       Command to GET account details using the authorization token received from the above command :

 curl -X GET https://[Your salesforce instance].salesforce.com/services/apexrest/ [URI Mapping] /[account Id] -H "Authorization: OAuth [Your authorization token]" -k  

For example :
 curl -X GET https://ap1.salesforce.com/services/apexrest/Account/0019000000Nah1a -H "Authorization: OAuth 00D90000000kIy777RYAQGVLW60UaT.yKMONqfjztdq1__6SGL70qOVFtwvYwj_4oykw7_QgKOTbl6jhZDAaYgtTW0ZR9THihS29MwPHAEuyxFbM" -k   


b.      Command to POST and create account using the authorization token received from the above command :

Suppose we use a JSON file with the following input:

  
 {  
             “Name”:”testaccount”,  
             “Phone”:”1234567890”  
 }  

 curl https://[Your salesforce instance].salesforce.com/services/apexrest/ [URI Mapping] /[account Id] -H "Authorization: OAuth [Your authorization token]" -H "Content-Type: application/json" -d @[Name of JSON file] -k  

For Example :
curl https://ap1.salesforce.com/services/apexrest/Account/ -H "Authorization:OAuth 00D90000000kIy777RYAQGVLW60UaT.yKMONqfjztdq1__6SGL70qOVFtwvYwj_4oykw7_QgKOTbl6jhZDAaYgtTW0ZR9THihS29MwPHAEuyxFbM" -H "Content-Type: application/json" -d @account.json -k  

This demo demonstrates how to create/query account using simple HTTP calls. This example can be extended further to accomplish more complex tasks.

Further JSON support makes REST Webservices excellent way to integrate with External Systems including legacy systems.  REST Webservices can be used to integrate two different Salesforce Org and let them talk seamlessly. In next part we will be covering How to use Rest Webservices to integrate two different Salesforce Orgs. 




Tuesday, June 25, 2013




Well here is a much awaited and the needed update for the PageBlockTable Enhancer plugin. Ever since I coded the first version, there were request for many features and this 2.2 version brings down some of them.

Here is what is new with this plugin
  1. Parameter to turn on and off Pagination.
  2. Support for specifying available page sizes.
  3. Support for choosing default page size on page load.

List o Parameters
  • targetPbTableIds : comma-separated Ids of the target Pageblock tables
  • paginate : Assign true if you want to use the pagination feature,default value is true.
  • pageSizeOptions : A comma seperated list of integer values that will displayed as dropdown for page size
  • defaultPageSize : Default page size that needs to be selected (at page load).
Ajax/Rerender support
  • This version brings in support for rendering, the earlier version wasn't able to handle this. So incase you are rerendering your table or the parent components, you can call the "initPageBlockTableEnhancer()" method from "oncomplete" even of your commandButtons/actionFunctions/actionSupport/commandLink .

    <apex:commandButton value="Rerender" reRender="mid" oncomplete="initPageBlockTableEnhancer()"/>
Basic Syntax
The basic syntax remains same, just few added params.

<c:PageBlockTableEnhancer targetPbTableIds="mid,mid2" paginate="true" defaultPageSize="5" pageSizeOptions="5,10,20,30,40,50,100"/>    
   <apex:pageBlock >   
     <apex:pageBlockTable value="{!accounts}" var="acc" id="mid">   
      <apex:column value="{!acc.Name}"/>   
     </apex:pageBlockTable>    
     <apex:pageBlockTable value="{!accounts}" var="acc" id="mid2">   
      <apex:column value="{!acc.Name}"/>   
     </apex:pageBlockTable>     
   </apex:pageBlock>  


Demo And Installation / Unmanaged Package: http://blogforce9dev-developer-edition.ap1.force.com/ProjectDetail?id=a0290000007rdwd
[Updated @ 27-Nov-2013 :  Bug Fixes related to sorting]

Thursday, June 6, 2013


What are wrapper classes?

Wrapper classes can be considered as user defined data types. Wrapper classes can enclose together many other variables/parameters to represent a object or a single entity. They can include primitive types, complex types, Sobject types and even other wrapper classes as their property.

Lets assume we want to define a Entity say "Student". So for this we have to define a Wrapper class "Student"with properties like RollNumber,Name,Email. The class will look like.

Public class Student{  
  public String RollNumber;  
  public String Name;  
  public String Email;  
 }  

Where we can use these wrapper classes ?

Lets consider a real life scenario where user is allowed to select some records from a pageblock table and is allowed to do some action on the selected records.

So in our case lets assume the Sobject is Account, user will be allowed to select some records from a list and say they will be allowed to delete the selected record using a button.



How to implement this ?

Well we can always fetch some records to the pageblocktable to display set of records in table, but how to bring back the selection to controller ? Well here comes the need of another property in picture which will bring back the selection to the controller. This can achieved by creating a extra checkbox field in sobject but doesnt sounds like a good plan. A new field just for selection ? well Wrapper classes will be a better option here. We will define a wrapper class with this additional property say "isSelected" and will use the same in the page.

So the wrapper class will look like

public class sObjectWrapper{  
  public boolean isSelected{get;set;}  
  public Account myAccount{get;set;}  
  public sObjectWrapper(Account myAccount,Boolean isSelected){  
   this. myAccount = myAccount;  
   this.isSelected = isSelected;  
  }  
 }  

Now how to populate this wrapper class ?

You may have to modify your code to populate List< sObjectWrapper > instead of List<SObject>. So lets say you have a method "getData" in controller that queries for the related records, you may want to modify the same to support wrappers.

So the controller will look something like this

public class WrapperDemo_Con {  
   /*List of wrappers*/  
   public List<sObjectWrapper> wrappers{get;set;}  
   /*Constructor*/  
   public WrapperDemo_Con(){  
     wrappers = getData();  
   }  
   /*method to delete the selected record*/   
   public void deleteRecords(){  
     List<Account> accToDel = new List<Account>();  
     for(sObjectWrapper wrap : wrappers){  
       /*Check if record is selected*/  
       if(wrap.isSelected){  
         accToDel.add(wrap.myAccount);  
       }  
     }  
     /*Delete the selected records*/  
     delete accToDel;  
     /*Referesh the data*/  
     wrappers = getData();  
   }  
   /*mehtod to query account and populate wrappers*/  
   private List<sObjectWrapper> getData(){  
     List<sObjectWrapper> wrappers = new List<sObjectWrapper>();  
     for(Account acc : [SELECT Name,Id,Phone, Description FROM Account]){  
       /*Create a new wrapper and add it to list*/  
       wrappers.add(new sObjectWrapper(acc,false));  
     }  
     return wrappers;  
   }  
   /*Wrapper class*/  
   public class sObjectWrapper{  
    public boolean isSelected{get;set;}  
    public Account myAccount{get;set;}  
    public sObjectWrapper(Account myAccount,Boolean isSelected){  
     this.myAccount = myAccount;  
     this.isSelected = isSelected;  
    }  
   }  
 }  

And the corresponding VF page will be

<apex:page controller="WrapperDemo_Con">  
   <apex:sectionHeader title="Demo" subtitle="Wrapper Class"/>  
   <apex:Form >  
     <apex:pageBlock title="Wrapper Demo">  
       <apex:pageBlockButtons >  
         <apex:commandButton value="Delete" action="{!deleteRecords}"/>  
       </apex:pageBlockButtons>  
       <apex:pageBlockTable value="{!wrappers}" var="wrap">  
         <apex:column headerValue="Select">            
           <apex:inputCheckbox value="{!wrap.isSelected}"/>  
         </apex:column>  
         <apex:column value="{!wrap.myAccount.name}"/>  
         <apex:column value="{!wrap.myAccount.phone}"/>  
       </apex:pageBlockTable>  
     </apex:pageBlock>  
   </apex:Form>  
  </apex:page>  


Now testing time! Select few records from the list and press the save button. The selected records should be delete d and page should reload with the current data set.

In a similar fashion you can wrap any Sobject or Even wrap another wrapper class to get desired result. May be something more complicated!