[SalesForce] PDF unable to load..when using oncomplete or rerender..Any Help..

I have created a VF page and used "render as pdf"

<apex:commandButton value="Save to Opportunity" action="{!savePdf}"  />

Its working fine when i am using above line without rerender and oncomplete but when i am adding rerender or oncomplete it is not working.I am able to save the PDF in attachment folder but when i am trying to open its showing "Unable to load document"

Even if i remove oncomplete and use Rerender then also its saving the attachment in Attachment object and when i view ,it is not loading and says "Unable to load document"

    <apex:commandButton value="Save to Opportunity" action="{!savePdf}"  oncomplete="myClose();"/>

Javascript Code

function myClose(){

    self.close();
    window.opener.location.href="/{!$CurrentPage.parameters.Id}";
 }

Class Code

public void savePdf() {

    PageReference pdf = Page.GenerateQuotePDF;
    pdf.getParameters().put('id',parentId);

    Attachment attach = new Attachment();

    Blob body;
    body = pdf.getContent();
    attach.Body = body;
    attach.Name = 'Opportunity'+ '.pdf';  
    attach.IsPrivate = false;
    attach.ParentId = parentId;
    attach.ContentType = 'application/pdf';
    insert attach; 

  }  

Please help..

Best Answer

A PDF document can only be rendered as a PDF once. If you "rerender" it, you're creating a new document for saving. When you load a saved PDF, it is already "complete" and has been "rendered". When you load it, you're loading a document with a mime type of "PDF". That's why those two key words are problematic for you in your code.

EDIT

Here's how to do the rest of what you want. You'll need to modify your controller to do it along with your VF page. Portions of the code came from http://iwritecrappycode.wordpress.com/.

In addition to the existing content, your VF Page should look something like this:

<apex:page controller="forceDownloadPDF" renderAs="{!renderAs}">
<h2>PDF Download example</h2>

<p>This is some content that could be displayed as a PDF or a regular web page depedning on the URL params. The valid URL params are as follows</p>
<table width="100%" cellpadding="5" cellspacing="5">
    <tr>
        <th>Name</th>
        <th>Type</th>
        <th>Default</th>
        <th>Required</th>
        <th>Description</th>
    </tr>
    <tr>
        <td>pdf</td>
        <td>String with a boolean value</td>
        <td>null/false</td>
        <td>false</td>
        <td>if passed in as a true the page will be rendered as a PDF. Otherwise displayed as HTML</td>
    </tr>
    <tr>
        <td>force_download</td>
        <td>String with a boolean value</td>
        <td>null/false</td>
        <td>false</td>
        <td>If true the user will be prompted to download the contents of the page. Suggested to be paired with pdf=true</td>
    </tr>
    <tr>
        <td>filename</td>
        <td>String (valid file name)</td>
        <td>'My PDF Report [todays date].pdf'</td>
        <td>false</td>
        <td>A name for the file. Only used if force_download=true</td>
    </tr>    
</table>

</apex:page>

You'll need to add something like what's below to your controller:

public class forceDownloadPDF {

    public string dudeName{get;set;}
    public string renderAs{get;set;}

    public forceDownloadPDF()
    {
        dudeName =  UserInfo.getName();

        //figure out if the user passed in the pdf url variable and if it is set to true.
        if(ApexPages.currentPage().getParameters().get('pdf') != null && ApexPages.currentPage().getParameters().get('pdf') == 'true') 
        {
            //if so, we are rendering this thing as a pdf. If there were other renderas options that were valid we could consider allowing the user to pass
            //in the actual renderAs type in the url, but as it stands the only options are pdf and null so no reason to allow the user to pass that in directly.
            renderAs = 'pdf';

            //figure out if we are forcing download or not.
            if(ApexPages.currentPage().getParameters().get('force_download') != null && ApexPages.currentPage().getParameters().get('force_download') == 'true') 
            {
                //setup a default file name
                string fileName = 'My PDF Report '+date.today()+'.pdf';

                //we can even get more created and allow the user to pass in a filename via the URL so it can be customized further
                if(apexPages.currentPage().getParameters().get('filename') != null)
                {
                    fileName = apexPages.currentPage().getParameters().get('filename') +'.pdf';
                }
                //here is were the magic happens. We have to set the content disposition as attachment.
                Apexpages.currentPage().getHeaders().put('content-disposition', 'attachemnt; filename='+fileName);
            }               
        }        
    }
}

If you call that page from a link it still opens in a new window & it forces the user to download the file. To get it to download and "close" the page, here's what you do:

ifrm = document.createElement("IFRAME"); 
ifrm.setAttribute("src", "/apex/yourPage?pdf=true&force_download=true&filename=My Happy File"); 
ifrm.style.width = 0+"px"; 
ifrm.style.height = 0+"px"; 
document.body.appendChild(ifrm);

Of course replace the 'yourPage' with the name of your visualforce page. The filename of course can be changed to be details from the record, or whatever you like. Now when the user clicks that button the javascript creates an invisible iframe and injects it into the DOM. Once it loads the user is prompted to download the file.

I believe that modifying kenjj776's code I've posted above with what you've already done should finish getting you to where you want to be.

If not, someplace, I used to have some button code that did this sort of thing, but can't seem to find it at the moment. You might want to look at the code for the standard quote button to see if that's of any help. I know there's also a post or two here on SF.SE on rendering to PDF & emailing the Pdf as an attatchment that you may want to search for as well as additional resources to look at.

Here's one in particular by mstOr that appears to provide a complete solution: How do I convert a visualforce page to a PDF?

The latter may perhaps give you the cleanest solution.