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
kito kidkito kid 

Generate CSV with apex and make it avaliable as link

I am new to Apex.

 

I want to generate CSV with apex from DB records with certain criteria.

And make it CSV avaliable as Link on the page to the user.

So that user can able to download it.

 

How can I achieve it? Any input will be helpful :D

 

Below are my current code for the step until getting recrod from DB.

 

 contactList = [
            Select c.AccountId,c.Email  From Contact c
        ];
        
        System.Debug('contactList: ' + contactList.size());
        
        //generate csv
        string header = 'AccountId, Email \n';
        string finalstr = header ;
        
        for(Contact c : contactList){
            string recordString = c.AccountId + ',' + c.Email + '\n';
            finalstr = finalstr + recordString;
        }

Advanz Knowledge SystemsAdvanz Knowledge Systems

Hi,

 

We have to use this attribute contentType="text/csv#filename.csv" in <apex:page> tag.

 

Whenever we will get records in this page it auomatically download the file as .csv in excel sheet.

 

Please go through the sample code which help you.

 

Visual Force:

 

<apex:page controller="case56" cache="true" contentType="text/csv#filename.csv" >"Case Number","Created Date"
<apex:repeat value="{!casestatus}" var="c">
"{!c.casenumber}",{!c.createddate}"
</apex:repeat>
</apex:page>

 

Apex Controller:

 

public with sharing class case56 {
List<case> a = new List<case>();
    public List<case> getcasestatus() {
    a = [select CaseNumber,createddate from case where Status='Working'];
        return a;
    }
}

 

kito kidkito kid

Hi Advanz,

Thanks for the reply.

 

I know I can make the file downloadable from VF page.

But the problem is if I write like that in VF, whenever the page is called, the file is downloaded.

 

I want to make the following steps to requirements.

When clicking certain button [ Generate CSV ],

1) generate CSV file

2) that CSV file might be posted to some external point via HTTP post.

3) make that CSV download link (which means user can download if he wishes) optional

 

That's why I want to generate a CSV and do other things with that CSV file.

Any suggestion ?

Michael_TorchedloMichael_Torchedlo

Kito,

 

If you are using a VF page rendered in CSV format, which is what Advanz does in his example, then maybe try the PageReference getContent() method.

 

Create a second VF page, which will show the user an <apex:outputLink>  tag which will be the download link.  Have it use the same controller (or controller extension) that you wrote for your first page and then insert a method that contains code something like this:

 

PageReference csvPage = Page.MyCSVPageName;   //MyCSVPageName is the name of the VF page that you have rendering in CSV format
Blob csvBlob = csvPage.getContent();

/* create & insert a document in Salesforce.com */
/* OR you can run your HTTP POST call here and use the Blob value as the body of the file you are posting */
Document tDoc = new Document();
tDoc.Name = 'MyCSVFileName';
tDoc.Type = 'csv';
tDoc.body = csvBlob;
tDoc.FolderId = '00l30000001CVtI';  /* id of whatever Salesforce document folder you want to use*/
tDoc.IsInternalUseOnly = FALSE;
insert tDoc;

/*after this, you can use the ID from your newly inserted document as a URL parameter for the download link*/

 

The download link url in Salesforce.com will be something like this:

https://c.cs15.content.force.com/servlet/servlet.FileDownload?file={!Document.id}

 

If instead of a Salesforce Document, you post the CSV file to an external directory, then you should already know in advance what the HTTP endpoint and filename will be, so you can use that URL in the <apex:outputLink> tag.

 

If this works, then it's the 2nd page that your user will actually be looking at, and that you will put in your page layout. The first page, rendered as CSV, is never directly visited.  It is only used to create a CSV file which is immediately saved for later, whenever the user decides to download it.

 

I hope my suggestion makes sense.

kito kidkito kid

Hi Micheal,

Thanks for the reply.

 

As I am new to Apex, I am lost between how to call the 2nd page of VF from the First page.

 

For now, my progress is whenever I go to 1st Page, the system ask to download the file.

1) I want to avoid asking the user to download.

2) I want to directly call the new method of getContent()method like you have provided from the First page.

3) Then go the Second page and show the link.

 

any references will be helpful for me.

Michael_TorchedloMichael_Torchedlo

Kito,

 

The Visualforce Developer's guide explains more details on how to use one controller on multiple pages.  Here is one example:

 

http://developer.force.com/cookbook/recipe/creating-a-wizard-with-visualforce-pages

 

If you post the code from your existing VF page and controller, then I may be able to suggest specific line changes.  The general idea is that both VF pages use the same Apex controller class (or controller extension class).  If you create a similar setup like this and then use the getContent() method in my previous post, it will work.

 

(Apex Controller)

public class mycontroller{

...

 

    //within the controller, Page.VFPage1 will give you the PageReference for VFPage1

    PageReference variableA = Page.VFPage1;

    PageReference variableB = Page.VFPage2;

 

}

 

 

VFPage1

<apex:page controller="mycontroller" >

...

 

 

VFPage2

<apex:page controller="mycontroller" >

...

Michael_TorchedloMichael_Torchedlo

Here is a plain example

 

Apex controller:

public class CSVcontroller{
    public ID DocId {get; set;}

    public CSVcontroller(){
    }

    public void autoRun(){
        PageReference csvPage = Page.MyCSVPageName;   
        Blob csvBlob = csvPage.getContent();

        /* create & insert a document in Salesforce.com */
        /* OR you can run your HTTP POST call here and use the Blob value as the body of the file you are posting */
        Document tDoc = new Document();
        tDoc.Name = 'MyCSVFileName';
        tDoc.Type = 'csv';
        tDoc.body = csvBlob;
        tDoc.FolderId = '00l30000001CVtI';  /* id of whatever Salesforce document folder you want to use*/
        insert tDoc;

        /*after this, you can use the ID from your newly inserted document as a URL parameter for the download link*/
        DocId = tDoc.id;
    
    }

}

 

VF Page name: MyCSVDownloadLink

<apex:page controller="CSVcontroller" action="{!autorun}" >
  <!-- Begin Default Content REMOVE THIS -->
  Click here to download the csv file:
    <apex:outputLink value="https://c.cs15.content.force.com/servlet/servlet.FileDownload?file={!DocId}" id="theLink">Download</apex:outputLink>
  <!-- End Default Content REMOVE THIS -->
</apex:page>

 VF Page: MyCSVPageName

<apex:page contentType="text/csv#filename.csv" controller="CSVcontroller" >
  <!-- Begin Default Content REMOVE THIS -->
  <h1>Congratulations</h1>
  This is your new Page: MyCSVPageName
  <!-- End Default Content REMOVE THIS -->
</apex:page>

 

To view this example, create these 3 components and then go straight to download link page: 

 

https://cs15.salesforce.com/apex/MyCSVDownloadLink

 

It uses the CSV page and saves as a document, but it's all hidden.  The only thing the user sees is the "MyCSVDownloadLink" page.  Obviously, in real use, this will insert a document every time the user loads the "MyCSVDownloadLink" page, so you will need to decide how many documents you want to store, and for how long, so that you don't exceed your storage limits.  You could add apex code to the controller to query and delete csv files that are no longer needed, or you could manage the files manually.