Friday 14 November 2014

Pagination with Wrapper Class ( with maintaing the state of selected records)

Problem :-

1) One thing I noticed is the Checkboxes don’t maintain state in pagination with StandardSetController if you check one, go to the next page, then go back. Checkbox will uncheck again.

2) StandardSetController only support List of Sobject and SOQL as parameter. Some time in our case we did not use the SOQL and Sobject. We need to create Wrapper class and need to show that wrapper class with pagination on Visual force page.


Solution :- 

So If we use the StandardSetController, the check-boxes don’t maintain state if you check one and then go to the next page. To solve this problem I have implemented custom Iterator.

Even in StandardSetController constructor we cant sent List of Wrapper.



Please check Working on below link :-
http://amitblog-developer-edition.ap1.force.com/apex/CustomPaginationDemo


Step 1:- Create Wrapper Class :-


global class ContactWrapper
{
public Boolean isSelected {get;set;}
public Contact cont{get;set;}        
    public ContactWrapper(Contact cont,Boolean isSelected)
    {
        this.cont= cont;
        this.isSelected= isSelected;
    }
    
}



Step 2:-  Create A Custom Iterator class which should implement Iterator class 

global class  CustomIterable implements Iterator<list<ContactWrapper>>

   list<ContactWrapper> InnerList{get; set;}
   list<ContactWrapper> ListRequested{get; set;}

   Integer i {get; set;} 
   public Integer setPageSize {get; set;} 

   public CustomIterable(List<ContactWrapper> lstAccWr)
   {
       InnerList = new list<ContactWrapper >(); 
       ListRequested = new list<ContactWrapper >();     
       InnerList = lstAccWr;
       setPageSize = 10;
       i = 0; 
   }   

   global boolean hasNext(){ 
       if(i >= InnerList.size()) {
           return false; 
       } else {
           return true; 
       }
   } 
   
   global boolean hasPrevious(){ 
       system.debug('I am in hasPrevious' + i);
       if(i <= setPageSize) {
           return false; 
       } else {
           return true; 
       }
   }   

   global list<ContactWrapper > next(){       
       system.debug('i value is ' + i);
       ListRequested = new list<ContactWrapper >(); 
       integer startNumber;
       integer size = InnerList.size();
       if(hasNext())
       {  
           if(size <= (i + setPageSize))
           {
               startNumber = i;
               i = size;
           }
           else
           {
               i = (i + setPageSize);
               startNumber = (i - setPageSize);
           }
           
           system.debug('i value is =====' + i);
           system.debug('i value is 2==== ' + (i - setPageSize));
           
           for(integer start = startNumber; start < i; start++)
           {
               ListRequested.add(InnerList[start]);
           }
       } 
       return ListRequested;
   } 
   
   global list<ContactWrapper > previous(){      
       ListRequested = new list<ContactWrapper >(); 
       system.debug('i value is previous before =====' + i);
       integer size = InnerList.size(); 
       if(i == size)
       {
           if(math.mod(size, setPageSize) > 0)
           {    
               i = size - math.mod(size, setPageSize);
           }
           else
           {
               i = (size - setPageSize);
           } 
       }
       else
       {
           i = (i - setPageSize);
       }
       
       system.debug('i value is previous =====' + i);
       system.debug('i value is 2previous ==== ' + (i - setPageSize));
       
       for(integer start = (i - setPageSize); start < i; ++start)
       {
           ListRequested.add(InnerList[start]);
       } 
       return ListRequested;
   }   
}
    


Step 3:- Create controller class :-


public with sharing class CustomPaginationDemo
{

public List<ContactWrapper> lstWrapper {get;set;}
public List<ContactWrapper> lstSetController{get;set;}

CustomIterable obj;

    public CustomPaginationDemo() 
    {
        lstWrapper =  new List<ContactWrapper>();
        lstSetController = new List<ContactWrapper>();

        List<Contact> lstContact = [select id,name from Contact limit 20];
        
        for(Contact cont : lstContact )
        {
            lstWrapper.add(new ContactWrapper(cont ,false));
        }

        obj = new CustomIterable (lstWrapper); 
        obj.setPageSize = 5;
        next();         
    }
    
    
        public Boolean hasNext {
            get 
            {
                return obj.hasNext();
            }
            set;
        }
        
        public Boolean hasPrevious {
            get 
            {
                return obj.hasPrevious();
            }
            set;
        }
        
        public void next() 
        {
            lstSetController = obj.next();
        }
        
        public void previous() 
        {
            lstSetController = obj.previous();
        }
    
}


Step 4:- Create Visual Force Page :-

<apex:page controller="CustomPaginationDemo">
<apex:form >
 <apex:pageBlock id="ThePage">
 
    <apex:pageBlockSection columns="1">
 
      <apex:pageBlockTable value="{!lstSetController }" var="obj" >
             <apex:column headerValue="Select">
                <apex:inputCheckbox value="{!obj.isSelected}"/>
             </apex:column> 
             <apex:column value="{!obj.cont.Name}" headerValue="Name"/> 
      </apex:pageBlockTable>
    
        <apex:outputPanel >
           <apex:commandButton value="<<Previous" action="{!previous}" rendered="{!hasPrevious}" reRender="ThePage" />
           <apex:commandButton value="Next >>" action="{!next}" rendered="{!hasNext}" reRender="ThePage" />
        </apex:outputPanel>  
        
    </apex:pageBlockSection>
 </apex:pageBlock>
</apex:form>

</apex:page>



    



Related Link :-

Standardsetcontroller Reference:- https://www.salesforce.com/us/developer/docs/pages/Content/apex_pages_standardsetcontroller.htm

https://www.salesforce.com/us/developer/docs/pages/Content/apex_ApexPages_StandardSetController_constructors.htm

Standardsetcontroller Eaxmple :-
http://blog.jeffdouglas.com/2009/07/14/visualforce-page-with-pagination/

Iterable Class Detail:-
 https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_iterable.htm


Thanks
Amit Chaudhary

Saturday 8 November 2014

Dynamic Tab In Salesforce ( CSS and apex:dynamicComponent )


Some time we need to create dynamic tab. This we can achieve with below way :-
1) By CSS
2) By <apex:dynamicComponent


DEMO 1:- By CSS 

Page :-

<apex:page controller="DynamicTabController" sidebar="false"  standardStylesheets="false" showHeader="false">
<head>
 <style type="text/css">

 .black_overlay{
       display: none;
       position: absolute;
       top: 0%;
       left: 0%;
       width: 100%;
       height: 100%;
       background-color:#F8F8F8  ;
       z-index:1001;
       -moz-opacity: 0.8;
       opacity:.80;
       filter: alpha(opacity=80);
  }
  .white_content {
      display: none;
      position: relative;
      z-index:1002;
      overflow: auto;
  }

    #layer1 
                {
                position: absolute;
                visibility: hidden;
                width: 800px;
                height: 450px;
                left: 50%;
                top: 20%;
                background-color: #ccc;
                border: 1px solid #000;
                padding: 10px;
                overflow:scroll;
               }
            
            #close 
            {
                float: right;
            } 

 
.tabs {
  position: relative;   
  min-height: 550px; /* This part sucks */
  clear: both;
  margin: 25px 0;
}
.tab {
  float: left;
}
.tab label {
  background: #eee; 
  padding: 10px; 
  border: 1px solid #ccc; 
  margin-left: -1px; 
  position: relative;
  left: 1px; 
}
.tab [type=radio] {
  display: none;   
}
.content {
  position: absolute;
  top: 28px;
  left: 0;
  background: white;
  right: 0;
  bottom: 0;
  padding: 20px;
  border: 1px solid #ccc; 
  overflow: auto;
  
}
[type=radio]:checked ~ label {
  background: white;
  border-bottom: 1px solid white;
  z-index: 2;
}
[type=radio]:checked ~ label ~ .content {
  z-index: 1;
}            
            
    </style>

</head>    

<apex:form style="none">

        <center>
          <div class="tabs">
            <apex:repeat value="{!lstAccount}" var="acc"> 
               <div class="tab">
                   <input type="radio" id="tab-{!acc.Name}" name="tab-group-1" checked="True" />
                   <label for="tab-{!acc.Name}">{!acc.Name}</label>
                    <div class="content">
                       <table width="100%">
                            <apex:repeat value="{!$ObjectType.Account.FieldSets.Account_FieldSet}" var="fieldSet"> 
                                <tr> 
                                    <td>
                                        {!fieldSet.Label}
                                    </td>   
                                    <td>
                                        <apex:inputField value="{!acc[fieldSet]}"/>
                                    </td>
                                </tr>   
                            </apex:repeat>
                       </table>
                    </div> 
                </div>
             </apex:repeat>
        </div>
        </center>
    
        
</apex:form>

</apex:page>

Class:-

public with sharing class DynamicTabController 
{
    public List<Account> lstAccount{get;set;}
    
    public DynamicTabController()
    {
        lstAccount=new List<Account>();

                String query = 'SELECT ';
                for(Schema.FieldSetMember f : this.getFields()) 
                {
                    query += f.getFieldPath() + ', ';
                }

                query += '  Id FROM Account limit 5 ';
                System.debug('query ------>'+query );

                lstAccount = Database.query(query);        

    }

    public List<Schema.FieldSetMember> getFields() 
    {
        return SObjectType.Account.FieldSets.Account_FieldSet.getFields();
    }

}


Live Demo Link :-
http://amitblog-developer-edition.ap1.force.com/apex/DynamicTab

DEMO 2:-  <apex:dynamicComponent >

Page :-

<apex:page controller="dynamicComponentDemoController">

<apex:form >
        <apex:pageBlock >
            <apex:pageBlockButtons location="bottom">
                <apex:inputText value="{!newTabName}"/>
                <apex:commandButton value="Add Tab" action="{!addTab}"/>
            </apex:pageBlockButtons>
            <apex:dynamicComponent componentValue="{!tabPanel}"/>

            <apex:dynamicComponent componentValue="{!MyPanel}"/>


        </apex:pageBlock>
</apex:form>

</apex:page>
Class:-

public with sharing class dynamicComponentDemoController {

    public static Component.Apex.tabPanel MyPanel {get;set;}
    
    public  dynamicComponentDemoController ()
    {
        MyPanel = new Component.Apex.tabPanel();
        MyPanel.switchType = 'client';

        List<Account> lstAccount = [select id,name,industry from account limit 5];
        
        integer idx = 0;
        for(Account acc : lstAccount )
        {
            idx ++;
            Component.Apex.Tab tab = new Component.Apex.Tab();
            tab.id = 'tab_First'+string.valueof(idx);
            tab.label = acc.Name;
           /* 
            Component.Apex.CommandButton command = new Component.Apex.CommandButton();
            command.value='Save';
            command.expressions.action='{!save}';
            tab.childComponents.add(command);

            Component.Apex.InputText t = new Component.Apex.InputText();
            t.expressions.value ='{!c.status}' ;
            tab.childComponents.add(t);
           */ 
                    
    
            Component.Apex.outputText f = new Component.Apex.outputText();
            f.value = 'Industry  :-'+acc.industry ;
            tab.childComponents.add(f);
            
            MyPanel.childComponents.add(tab);
        }
    }
    
    public void addTab() {
        names.add(newTabName);
    }
 
    string[] names = new string[0];
    public String newTabName { get; set; }
    
    public Component.Apex.TabPanel getTabPanel() 
    {
        Component.Apex.TabPanel panel = new Component.Apex.TabPanel();
        panel.switchType = 'client';
        for(integer idx = 0; idx < names.size(); idx++) {
            Component.Apex.Tab tab = new Component.Apex.Tab();
            tab.id = 'tab'+string.valueof(idx);
            tab.label = names[idx];
            
            Component.Apex.CommandButton command = new Component.Apex.CommandButton();
            command.value='Save';
            command.expressions.action='{!save}';
            tab.childComponents.add(command);
    
            Component.Apex.outputText f = new Component.Apex.outputText();
            f.value = 'Description';
            tab.childComponents.add(f);

            Component.Apex.InputText t = new Component.Apex.InputText();
            t.expressions.value ='{!c.status}' ;
            tab.childComponents.add(t);
            
            panel.childComponents.add(tab);
        }
        return panel;
    }
    
    public void save()
    {
    }

    
}

Live Demo Link :- http://amitblog-developer-edition.ap1.force.com/dynamicComponentDemo

Thursday 6 November 2014

Syncing custom fields between quotes and opportunities (Custom Quote Sync)



Some time we need to sync Opportunity Line Item and Quote Line Item.When we create Quote automatically  Opportunity line item created as Quote Line Item. But Some time we also need to sync custom field.

Requirement :-

I would like to sync between opportunity line item and quote line item. I have a few custom fields defined in addition to standard fields in both quote line item and opportunity line item objects. Custom fields in both objects are exact replica.

Solution :-
For above requirement I have created the below trigger :-

/*
***********************************************************************
Created By    :- Amit Chaudhary
Created Date  :- 06 NOV 2014
Desc          :- Syncing custom fields between quotes and opportunities 
***********************************************************************
*/

trigger QuoteLineItemTrigger on QuoteLineItem (after insert){


    map<string,string> mapQuoteOppty=new map<string,string>();
    string JSONContent=Json.Serialize(Trigger.New);
    JSONParser parser =JSON.createParser(JSONContent);
    list<string> OpptyLineId=new list<string>();
    list<string> QuoteLineId=new list<string>();
    System.debug('parser-------->'+parser );
    
    while (parser.nextToken() != null) 
    {
        if(parser.getCurrentToken()==JSONToken.VALUE_STRING && parser.getCurrentName()=='OpportunityLineItemId')
        OpptyLineId.add(parser.getText());
            if(parser.getCurrentToken()==JSONToken.VALUE_STRING && parser.getCurrentName()=='Id')
                QuoteLineId.add(parser.getText());
                parser.nextToken();
                    if(parser.getCurrentToken()==JSONToken.VALUE_STRING && parser.getCurrentName()=='OpportunityLineItemId')
                        OpptyLineId.add(parser.getText());
                        if(parser.getCurrentToken()==JSONToken.VALUE_STRING && parser.getCurrentName()=='Id')
                            QuoteLineId.add(parser.getText());
    }

    System.debug('OpptyLineId-------->'+OpptyLineId);
    System.debug('QuoteLineId-------->'+QuoteLineId);
    
    integer iCount=0;
    for(string strOppLineId : OpptyLineId)
    {
        string iQuoteLineId=QuoteLineId[iCount];
        mapQuoteOppty.put(iQuoteLineId,strOppLineId);
        iCount++;
    }
    Set<Id> SetOppId=new Set<Id>();
    Set<Id> SetQuoteId=new Set<Id>();
    for(QuoteLineItem QLI:trigger.new)
    {
        SetQuoteId.add(QLI.QuoteId);
    }
    List<Quote> Lstquotes =[select id, OpportunityId, isSyncing from Quote where Id in :SetQuoteId];
    for(Quote Qt:Lstquotes)
    {
        SetOppId.add(Qt.OpportunityId);
    }
    
    List<OpportunityLineItem> lstOLI=[select Id, OpportunityId,Negotiated__c,End_Date__c,Start_Date__c from OpportunityLineItem where OpportunityId in:SetOppId];
    
    Map<Id,OpportunityLineItem> MapOLI=new Map<Id,OpportunityLineItem>([select Id,Negotiated__c, OpportunityId, End_Date__c,Start_Date__c  from OpportunityLineItem where OpportunityId in:SetOppId]);
    Map<Id,QuoteLineItem > MapQLI=new map<Id,QuoteLineItem>([Select Id, Negotiated__c, End_Date__c,Start_Date__c from QuoteLineItem where QuoteId in:SetQuoteId]);
    
    list<QuoteLineItem> updateQuoteLineItem =new list<QuoteLineItem >();
    for(QuoteLineItem qli:MapQLI.values())
    {
       System.debug('&&&&'+mapQuoteOppty);
       if(mapQuoteOppty.get(qli.id)!=null)
       {
          String OppID = mapQuoteOppty.get(qli.id);
          OpportunityLineItem OLI = MapOLI.get(OppID);
          
          qli.End_Date__c=OLI.End_Date__c;
          qli.Start_Date__c=OLI.Start_Date__c;   
          qli.Negotiated__c= OLI.Negotiated__c;

          updateQuoteLineItem.add(qli);
            
       }
    }
    update updateQuoteLineItem;
    
}






Related Link :-

Check this in AppExchange
https://sites.secure.force.com/appexchange/listingDetail?listingId=a0N30000003IlfVEAS
Custom Quote Sync
App by Force.com Labs 11/2/2010


Thanks
Amit Chaudhary

Dynamic field mapping using Custom Settings



Some time we need to pass one object information to another object. So in this regards developer needs to write a trigger / apex code and needs to define each column mapping in the code. But it may be possible that in future field mapping will change or some new fields will introduce. For that we again need to change code.

In that case we need to create a dynamic field mapping between two object. That functionality  we can achieve with custom setting.
 In my last project i have done some code for same functionality  

Requirement :-

As per client requirement he want to store the Lead information in Pre - Lead and then he want to convert the pre- lead into Lead after some validation. 

Solution :

So for above requirement we have created a object Pre-lead and on same object we have created a button convert lead. while converting the pre- lead into lead we need to provide dynamic field mapping between two object. For that i have created the custom setting "MyLeadToLeadMapping__c" with one custom field "Lead_Field_API_Name__c"



After that i have added the field mapping in custom setting



Code :---

public with sharing class ConvertMyLead
{
public Boolean showmessage{get;set;}
public string MyLeadid{get;set;}
public Lead LeadObj;
string qry = '';
    Map<string, string> MapMappingTable=new map<string,string>();

    public Pagereference MapLeadfields()
    {
        Pagereference pageref;
        Savepoint sp = Database.setSavepoint();
        try
        {
LeadObj=new Lead();
MyLeadid=ApexPages.currentPage().getParameters().get('MyLeadid');
getAllMapping();
qry = 'select ' + qry + 'id FROM My_Lead__c where id =: MyLeadid';
My_Lead__c MyLead = Database.query(qry);

for(String sMyLeadField: MapMappingTable.keySet())
{
String sLeadField = MapMappingTable.get(sMyLeadField);
LeadObj.put(sLeadField, MyLead.get(sMyLeadField));
}

LeadObj.OwnerID = UserInfo.getUserId() ;
LeadObj.status='new';
insert LeadObj;
showmessage=true;
pageref=new Pagereference('/'+LeadObj.Id);
return pageref;
        }
        catch(Exception ex)
        {
            Database.rollback(sp);
            ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.ERROR, ex.getMessage());
            Apexpages.addMessage(msg);
            return null;
       }
    }
 
    public Map<string,string> getAllMapping()
    {
        qry ='';
        try{
             for (MyLeadToLeadMapping__c mappingTableRec : MyLeadToLeadMapping__c.getall().Values())
             {
                if (mappingTableRec.Name != null && mappingTableRec.Lead_Field_API_Name__c != Null )
                {
                    MapMappingTable.put(mappingTableRec.Name , mappingTableRec.Lead_Field_API_Name__c);
                    qry += mappingTableRec.Name + ',';
                }
             }
        }
        catch(exception ex)
        {
            ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.ERROR, ex.getMessage());
            Apexpages.addMessage(msg);
        }
        return MapMappingTable;
    }
 
    public PageReference goBack()
    {
      PageReference pf = new PageReference('/'+MyLeadid);
      return pf;
    }

    public boolean getHasErrors()
    {
        return ApexPages.hasMessages(ApexPages.severity.ERROR);
    }
}


Thanks,
Amit Chaudhary