Search code examples
salesforceapexvisualforcesoqlmergefield

Merge fields won't show on visualforce page


I just started learning Apex recently, and there's still a lot of topics that are hard for me to navigate at this time. I've searched everywhere for a solution that works, but I still haven't been able to figure it out.

I've created a button on my Salesforce org that renders a PDF from a visualforce page, and attaches it to the record as a File. This is to be used with Docusign later on to capture signatures for contracts. The problem is that, when using merge fields in the VF page, they either do not show at all, or I get this exception: "sObject row was retrieved via SOQL without querying the requested field".

Now, the exception explicitly says that I need to query the fields, and this is what I've found I need to do to make this work, but I have not been able to figure out how to do this properly. I've tried running a query in several places in my controller extension to no avail (I am using a standardController that SF created for my custom object).

Here's my extension's code:

public class attachPDFToQuote {
    
    public final i360__Quote__c q {get; set;} //Quote object
     
   
    
    //constructor
    public attachPDFToQuote (ApexPages.StandardController stdController) {
        q = (i360__Quote__c)stdController.getRecord(); 
        
        /* for(i360__Quote__c query:[SELECT Id, Correspondence_Name__c, Name FROM i360__Quote__c WHERE Id=: q.Id]){
      
      System.debug(i360__Quote__c.Correspondence_Name__c);
      }*/
        
    }
     
    
    public PageReference attachPDF() {
    
   /* for(i360__Quote__c query:[SELECT Id, Correspondence_Name__c, Name FROM i360__Quote__c WHERE Id=: q.Id]){
      
      System.debug(i360__Quote__c.Correspondence_Name__c);
      }*/
    
        //generate and attach the PDF document
        PageReference pdfPage = Page.ProjectAgreement;
        Blob pdfBlob; //create a blob for the PDF content
        if (!Test.isRunningTest()) { //if we are not in testing context
            pdfBlob = pdfPage.getContent(); //generate the pdf blob
        } else { //otherwise, we are in testing context. Create the blob manually.
            pdfBlob = Blob.valueOf('PDF');
        }
        
        
        ContentVersion cvAttach = new ContentVersion(ContentLocation= 'S');
        cvAttach.PathOnClient= 'Project Agreement.pdf';
        cvAttach.Title= 'Project Agreement';
        cvAttach.VersionData= pdfBlob;
        insert cvAttach;
        
        Id conDoc = [SELECT ContentDocumentID FROM ContentVersion WHERE Id=: cvAttach.Id].ContentDocumentId;
        ContentDocumentLink ConDocLink = new COntentDocumentLink();
        conDocLink.LinkedEntityId= q.Id;
        conDocLink.ContentDocumentId= conDoc;
        conDocLink.ShareType= 'V';
        insert conDocLink;
       
        
        //redirect the user
        PageReference pageWhereWeWantToGo = new ApexPages.StandardController(q).view(); //redirect the User back to the Quote detail page
        pageWhereWeWantToGo.setRedirect(true); //indicate that the redirect should be performed on the client side
        return pageWhereWeWantToGo; //send the User on their way
    }

}

I kept the commented code where I try to query the object fields so they show in VF. I also tried a couple of different ways, but nothing seems to work. Please let me know if I need to add anything else.

Thank you!


Solution

  • You didn't post your Visualforce page's code.

    Even if it's same page (if your apex class is used in ProjectAgreement VF as <apex:page standardController="i360__Quote__c" extensions="attachPDFToQuote" - the act of grabbing a PDF version of the page counts as callout, a separate http traffic to fresh instance of the page so to speak.

    So I suspect you need something like

    PageReference pdfPage = Page.ProjectAgreement;
    pdfPage.getParameters().put('id', q.Id);
    Blob = pdfPage.getContent();
    

    If that works... next step would be to look at your VF code.

    If the page has merge fields such as {!i360__Quote__c.Name}, {!i360__Quote__c.Correspondence_Name__c} then magic should happen. Salesforce should figure out which fields are needed by looking at your VF page and silently query them for you. So you wouldn't even need the query in your constructor, you could just save stdController.getId() to class variable and then use that id in pdfPage.getParameters().set(...)

    But if your VF page has references to {!quote.Correspondence_Name__c} then you need to keep the explicit query in there.