+ Start a Discussion
AndyPandyAndyPandy 

Dynamic VF Page - Referencing $User.ID Merge Field

Hi All,

 

I have sorted out automating a daily upload of 40+ pdf files in a folder called “Daily Sales” within the SFDC “Documents” standard object; each pdf file is named a particular SFDC $User.ID.

 

e.g. 00920000002QgZe.pdf

 

I am trying to create a “dynamic” VF page, which displays the pdf related to the running user – as their pdf will be called $User.ID.pdf.  So I was hoping there would be a way of the VF Page being (in lay terms, not APEX Code): src=”[Salesforce Documents Folder.ID] \ [$User.ID.pdf]” – where the Folder.ID will be constant, and the $User.ID merge field will create the "dynamic-ness" of the page - basically a dynamic file path.

 

Having tried to play around with it, it seems that "file paths" is not the way in which SFDC works with Documents - so would anyone know if it would be possible for me to create this dynamic page - and if so provide some fairly detailed instructions please (I am a noob with VF).

 

Many thanks indeed,

 

Andy

bob_buzzardbob_buzzard

You can do this, but its a two stage process.

 

First you'll need to extract the id of the document in question via a SOQL query in your controller:

 

// property for doc
public Document doc;

public Document getDoc()
{
  Folder myFolder=[select id from Folder where DeveloperName='My Folder'];  // change name as appropriate
  String docName=UserInfo.GetUserId() + '.pdf';

  doc : [select id, Name, Description, ContentType, BodyLength 
		from Document 
		where FolderId=:myFolder.id
		and Name=:docName];
}

 

and then in the page you can use the URLFOR function to generate the link on the page:

 

<apex:outputlink value="{!URLFOR($Action.Document.Download, doc.id)}">Click to view</apex:outputlink>

 

I haven't compiled this, but it should be close.

 

AndyPandyAndyPandy

Thank you for your reply Bob - really appreciate it.

 

Just to confirm - the URLFOR function - would that mean that the resultant VF Page would display a link when accessed, which, once clicked, would display the relevant pdf, based on the $User.ID of the logged on user?

 

If so, this is very close to what I want, but rather than the VF Page displaying a link to click, I would like it to display the actual page straight away (without having to click a link).

 

Is that possible?

 

The reason being, I'm only creating a VF Page as this, ultimately, needs to be a Dashboard item - so this is just to allow me to add the pdf to a dashboard (via referencing a VF Page).

 

Thanks again,

 

Andy

bob_buzzardbob_buzzard

Yes, the controller figures out the document details and the urlfor generates the URL to it.  If you want to dive straight into it, I'd suggest use of a page action.  E.g.

 

<apex:page controller="mycontroller" action="{!URLFOR($Action.Document.Download, doc.id)}">
</apex:page>

 

This means that when the page is loaded, before anything is rendered it will figure out the doc and carry out a server side redirect to the download page.  As long as the browser has the correct plugins it will display in the page.

AndyPandyAndyPandy

Thanks again Bob - I really do appreciate your assistance with this.

 

As mentioned - I'm pretty new to all of this - so, my first effort has returned an error: "Error: Cyclic page or component references '/apex/tmsales' are not allowed"

 

I have created a new VF Page in my Sandbox area (by typing into the address bar: https://cs4.salesforce.com/apex/tmsales and then creating that page.  Then, going to edit my page, I have typed in:

 

<apex:page >
// property for doc
public Document doc;

public Document getDoc()
{
  Folder myFolder=[select id from Folder where DeveloperName='My Folder'];  // change name as appropriate
  String docName=UserInfo.GetUserId() + '.pdf';

  doc : [select id, Name, Description, ContentType, BodyLength 
        from Document 
        where FolderId=:myFolder.id
        and Name=:docName];
}
<apex:page controller="mycontroller" action="{!URLFOR($Action.Document.Download, doc.id)}">
</apex:page>
</apex:page>

Clearly, I'm doing something very wrong - would you be able to help me out with this?  Apologies for my ignorance with APEX.

 

Many thanks,

 

Andy

bob_buzzardbob_buzzard

The Apex needs to go into a controller rather than the page itself.

 

Page:

 

<apex:page controller="mycontroller" action="{!URLFOR($Action.Document.Download, doc.id)}">
</apex:page>

 

Controller:

 

public class MyController
{
   // property for doc
   public Document doc {get; set;}

   public MyController()
   {
     Folder myFolder=[select id from Folder where DeveloperName='My Folder'];  // change name as appropriate
     String docName=UserInfo.GetUserId() + '.pdf';

     doc : [select id, Name, Description, ContentType, BodyLength 
           from Document 
           where FolderId=:myFolder.id
           and Name=:docName];
   }
}

 

AndyPandyAndyPandy

Aha!  Thank you!

 

OK - so I've now gone to Setup > App Setup > Develop > APEX Classes to add in my controller (is that correct?).

 

When copying your code:

 

public class MyController
{
   // property for doc
   public Document doc {get; set;}

   public MyController()
   {
     Folder myFolder=[select id from Folder where DeveloperName='My Folder'];  // change name as appropriate
     String docName=UserInfo.GetUserId() + '.pdf';

     doc : [select id, Name, Description, ContentType, BodyLength 
           from Document 
           where FolderId=:myFolder.id
           and Name=:docName];
   }
}

 I initially got the error: "Error: Compile Error: expecting a semi-colon, found ':' at line 11 column 9"

 

When changing the ":" to a ";" in that line, which was:

 

doc : [select id, Name, Description, ContentType, BodyLength

 I then got the error: "Error: Compile Error: Expression cannot be a statement at line 11 column 6"

 

Same line as the above one.

 

Any ideas (sorry about this); thanks again for your help,

 

Andy

bob_buzzardbob_buzzard

Typo on my part - that should be doc = 

AndyPandyAndyPandy

Great - thank you, that has worked, and both the VF Page and the Controller have saved correctly - thank you so much!

 

HOWEVER...

 

I've navigated to the VF Page (https://c.cs4.visual.force.com/apex/tmsales) and it shows the following error:

 

Visualforce Error

 


System.QueryException: List has no rows for assignment to SObject

 

Class.MyController.: line 8, column 22 External entry point

 

Line 8 of the Class is:

 

  Folder myFolder=[select id from Folder where DeveloperName='Daily Sales'];  // change name as appropriate

So now I'm not sure what is wrong?!

bob_buzzardbob_buzzard

Have you checked that is the developer name of the folder?  Developer names usually don't have spaces or have underscores in the name.

 

You can change it to use the friendly name via:

 

Folder myFolder=[select id from Folder where Name='Daily Sales'];

 

AndyPandyAndyPandy

Brilliant - thanks again Bob,

 

We've now moved on to yet another small issue - after making your change above, and using:

 

Folder myFolder=[select id from Folder where Name='Daily Sales'];

I then navigated to the VF Page, and receieve a new error:

 

"System.QueryException: List has no rows for assignment to SObject

 

Class.MyController.: line 11, column 12 External entry point"

 

This refers to line:

 

 doc = [select id, Name, Description, ContentType, BodyLength

Sorry I'm so bad at this - but thank you again for persevering for me!

bob_buzzardbob_buzzard

This implies that there isn't a document called <userid>.pdf in that folder.  Its worth adding some debug lines to check that the name is constructing correctly etc.