function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
FrancisAFrancisA 

Custom list button to add existing records in a related list

Hi,

I have 1 custom object "Loan__c" with master-detail relationship to Account (used for loan of equipments).
I am planning to use the Asset object to manage my stock of loan equipments.
I created a custum field "LoanRef__c" into Asset with look-up relationship to the Loan__c object.

I have a related list "Assets" in the "Loan__c" object - I'd like to add a custom list button there to add existing asset records to this loan. When clicked, the list of all existing asset records must be shown with ability to check the ones I want to add to the loan.

I guess I need to develop an apex class + visual force page.
I'm a novice with apex and visual force but I tried to adapt some similar codes found on the forum, with no success.

Any idea?

Thanks
Best Answer chosen by FrancisA
Bryan JamesBryan James
Couldnt do this with a list button as that resides on the asset object itself so it wont be able to tell the id of the parent loan record until it has been assigned which kind of negates the purpose I would think. That being said it can be done when referencing a Visualforce page using a detail button. As such here is the code I put in place and tested. 

<!------------Visualforce----------->
<apex:page standardController="Loan__c" extensions="ViewAvailableAssets">
   <apex:form >  
    <apex:pageBlock >
        
            <apex:pageBlockButtons >
                          
                <apex:commandButton action="{!updateAssets}" value="Update Assets"/>                       
                
                </apex:pageBlockButtons>
         
            <apex:pageBlockSection >
                <apex:pageBlockTable title="All Assets" var="a" value="{!allAssets}">
                    <apex:column headerValue="Select">
                        <apex:inputCheckbox value="{!a.selected}" />
                    </apex:column>
                    <apex:column value="{!a.asset.Name}" headerValue="Asset Name"/>
                    
                </apex:pageBlockTable>
                
            
            </apex:pageBlockSection>
        
    </apex:pageBlock>
        </apex:form>  
    
</apex:page>


<!----------End Visualforce----------->

/*******************Apex********************/
public class ViewAvailableAssets {
    public List<Asset> selectedAssets;
    public List<AssetRecord> allAssets{get;set;}
    public ViewAvailableAssets(ApexPages.StandardController controller){
        populateAllAssets();
    }
    
    /**
     * This method populates the allAssets list with
     * objects built in our inner class.
     */
    public void populateAllAssets()
    {
         allAssets = new List<AssetRecord>();
        List<Asset> assets = [Select Name From Asset Where LoanRef__c = null Order By Name];
        for(Asset a: assets){
            allAssets.add(new AssetRecord(a));            
        }
    }
    /**
     * This method is called from a button push on the visualforce page.
     * when called it checks the status of  the selected attribute in in all
     * our AssetRecord objects. If they are true it places a copy of the Asset
     * record associated to that object in our selectedAssets list which is a list
     * of Asset records. It then updates the asset records and redirects to the 
     * loan record that started the process.
     */
    public PageReference updateAssets(){
        selectedAssets  = new List<Asset>();
        String loanId = ApexPages.currentPage().getParameters().get('id');
        Loan__c loan = [Select Id From Loan__c Where Id = :loanId];
        for(AssetRecord ar : allAssets)
        {
            system.debug(ar.selected);
            if(ar.selected)
            {
                Asset asset = ar.asset;
                asset.LoanRef__c = loanId;
                selectedAssets.add(asset);
            }
        }
        update selectedAssets;
        PageReference pr = new ApexPages.StandardController(loan).view();
        pr.setRedirect(true);
        return pr;
    }
    
    /**
     * This inner class is used to hold a single asset record and
     * associate it to a boolean variable, and creates an object of type AssetRecord.
     */
    public class AssetRecord {
        public Boolean selected {get;set;}
        public Asset asset {get;set;}
        /**
         * Constructor Method.
         * sets the objects variables.
         * @param asset an Asset Record
         */ 
        public AssetRecord(Asset asset){
            selected = false;
            this.asset= asset;
        }
    }
}


/*******************End Apex********************/
When a the detail button is pushed from the Loan Object
User-added image

The visualforce page opens loading all the assets that do not have a loan assigned to them.
Select the assets that will be assigned and click the "Update Assets" button.
User-added image

The assets will be assigned to the loan and the page will redirect back to the loan record.
User-added image
 

All Answers

Bryan JamesBryan James
Couldnt do this with a list button as that resides on the asset object itself so it wont be able to tell the id of the parent loan record until it has been assigned which kind of negates the purpose I would think. That being said it can be done when referencing a Visualforce page using a detail button. As such here is the code I put in place and tested. 

<!------------Visualforce----------->
<apex:page standardController="Loan__c" extensions="ViewAvailableAssets">
   <apex:form >  
    <apex:pageBlock >
        
            <apex:pageBlockButtons >
                          
                <apex:commandButton action="{!updateAssets}" value="Update Assets"/>                       
                
                </apex:pageBlockButtons>
         
            <apex:pageBlockSection >
                <apex:pageBlockTable title="All Assets" var="a" value="{!allAssets}">
                    <apex:column headerValue="Select">
                        <apex:inputCheckbox value="{!a.selected}" />
                    </apex:column>
                    <apex:column value="{!a.asset.Name}" headerValue="Asset Name"/>
                    
                </apex:pageBlockTable>
                
            
            </apex:pageBlockSection>
        
    </apex:pageBlock>
        </apex:form>  
    
</apex:page>


<!----------End Visualforce----------->

/*******************Apex********************/
public class ViewAvailableAssets {
    public List<Asset> selectedAssets;
    public List<AssetRecord> allAssets{get;set;}
    public ViewAvailableAssets(ApexPages.StandardController controller){
        populateAllAssets();
    }
    
    /**
     * This method populates the allAssets list with
     * objects built in our inner class.
     */
    public void populateAllAssets()
    {
         allAssets = new List<AssetRecord>();
        List<Asset> assets = [Select Name From Asset Where LoanRef__c = null Order By Name];
        for(Asset a: assets){
            allAssets.add(new AssetRecord(a));            
        }
    }
    /**
     * This method is called from a button push on the visualforce page.
     * when called it checks the status of  the selected attribute in in all
     * our AssetRecord objects. If they are true it places a copy of the Asset
     * record associated to that object in our selectedAssets list which is a list
     * of Asset records. It then updates the asset records and redirects to the 
     * loan record that started the process.
     */
    public PageReference updateAssets(){
        selectedAssets  = new List<Asset>();
        String loanId = ApexPages.currentPage().getParameters().get('id');
        Loan__c loan = [Select Id From Loan__c Where Id = :loanId];
        for(AssetRecord ar : allAssets)
        {
            system.debug(ar.selected);
            if(ar.selected)
            {
                Asset asset = ar.asset;
                asset.LoanRef__c = loanId;
                selectedAssets.add(asset);
            }
        }
        update selectedAssets;
        PageReference pr = new ApexPages.StandardController(loan).view();
        pr.setRedirect(true);
        return pr;
    }
    
    /**
     * This inner class is used to hold a single asset record and
     * associate it to a boolean variable, and creates an object of type AssetRecord.
     */
    public class AssetRecord {
        public Boolean selected {get;set;}
        public Asset asset {get;set;}
        /**
         * Constructor Method.
         * sets the objects variables.
         * @param asset an Asset Record
         */ 
        public AssetRecord(Asset asset){
            selected = false;
            this.asset= asset;
        }
    }
}


/*******************End Apex********************/
When a the detail button is pushed from the Loan Object
User-added image

The visualforce page opens loading all the assets that do not have a loan assigned to them.
Select the assets that will be assigned and click the "Update Assets" button.
User-added image

The assets will be assigned to the loan and the page will redirect back to the loan record.
User-added image
 
This was selected as the best answer
FrancisAFrancisA
Hy Bryan
Wow, this works perfectly.
Thank you so much!
FrancisAFrancisA
Hi,

Me again.

How would your write a good test for this Apex class?

Thanks!
Enrique DiazEnrique Diaz
Hello @Bryan James
I know this has been some time you share this code here. I tryied to use it but I have and error while saving the Apex class 'ViewAvailableAssets'
Error: Compile Error: Missing '<EOF>' at 'public' at line 13 column 5

Could you or some one tell me why this is happening
many thx