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
bikla78bikla78 

Help with VF Page Controller



I have built a controller and apex page that is supposed to display all meetings associated with the contact on the current page where the meeting type is a "Client- Event Meeting".  Good news is my page shows up but  I have 3 issues

 

   1. How come the contact name and company name does not appear when I have it referenced in my APEX tag.
  

   2. How can I have this behave the same way as related list objectso that when I click on subject, name or company it takes me

        directly to the object like a standard hyperlink
 

   3. How can I add this Visualforce page as a button on the contact page called “Client Meetings” so that when someone

      go to the John Do contact record, and they click this button, it will display all the events associated with him in the current page

 

This is my first real VF page assignment so please bare with me

 

 

<apex:page controller="ActivityController">
<apex:pageBlock >
<apex:pageBlockTable value="{!Activities}" var="a">
<apex:column value="{!a.subject}"/>
<apex:column value="{!a.type}"/>
<apex:column value="{!a.owner.name}"/>
<apex:column value="{!a.who.name}"/>
<apex:column value="{!a.what.name}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

 

public class ActivityController 
{
Public Event[] getActivities()
{
return [Select id, subject, what.name, who.name, type, activitydate,owner.name from Event
where whoid = :System.currentPageReference().getParameters().get('id')and type = 'Client Meeting (Event)'];
}




}

Message Edited by bikla78 on 07-14-2009 11:19 PM
Message Edited by bikla78 on 07-14-2009 11:19 PM
Best Answer chosen by Admin (Salesforce Developers) 
JimRaeJimRae

Did you set security on the page and controller to all other users to access it?

Go to Setup | Develop | Apex Classes

Select your class by the name, you will see a button called "Security" that allows you to specify which profiles can access the class.

 

 For the pages, Go to  Setup | Develop | Pages

 

You will see a "Security" link next to each page, again this allows you to specify which profiles can access the page.

 

That would be my guess as to the issue.

All Answers

sforce2009sforce2009

1. use it as whoID.Name not who.Name

2. <apex:column><apex:outputLink ......></apex:column>//check the syntax of apex hyper link

3. You can use a custom button and associate that with your VF page

 

bikla78bikla78

I modified the page and the controller but it is not pulling up the whoid (contact record) and the whatid (company record) into the field

 

<apex:page controller="ActivityController">
<apex:pageBlock >
<apex:pageBlockTable value="{!Activities}" var="a">
<apex:column value="{!a.subject}"/>
<apex:column value="{!a.type}"/>
<apex:column value="{!a.ownerid}"/>
<apex:column value="{!a.whoid}"/>
<apex:column value="{!a.whatid}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
public class ActivityController
{

public Event[] getActivities()
{
return [Select id, subject,whatid, whoid, type, activitydate,ownerid from Event
where type = 'Client Meeting (Event)' and whoid = :System.currentPageReference().getParameters().get('contact.id')];
}




}
Message Edited by bikla78 on 07-22-2009 01:28 PM
sforce2009sforce2009

1. Seems your query has something wrong

2. remove the where condition and test the query. It should work

3. If it works, you might have to escape the ( characters

4. Take the id parameter in a string and apply to query

bikla78bikla78
When I take out the where statement, the good news is, it brings up the whoid and whatid but it brings up everything in the database. I need to only bring up one that is on the current page.  Meaning, if go to a contact record and click a button, the page would display all the events for that contact record only. How can I do this?
sforce2009sforce2009

string currId = //give current page references contact id which you pass thru URL

list<Event> lstEvent = [select fieldname from Even where whoId =: currID] ;

 

bikla78bikla78

I updated it and it still doesn't seem to bring in the records associated with that contact. I created a custom link so that when I click on it, it launches the apex page from the contact layout. I can change it to a list<> but i think it would have the same result..any ideas? thanks again

 

public class ActivityController
{
    Public Event[] getActivities()
    {
      string currId =ApexPages.currentPage().getParameters().get('id');
       return [Select id, subject, what.id, who.id, type, activitydate from Event
               where whoid=: currid and type= 'Client Meeting (Event)'];

    }



 
}

JimRaeJimRae

Is the VF code for your page the full code?  Where are you trying to view the page from?  I think the issue is that you are not getting any contactid for your filter (it is null), and that is why you don't return any results.

 

 

bikla78bikla78

Hi Jim,

 

My original objective was to seperate the related list into an  event history and task history under a contact record and replace the stnadard activity history. I was told that I could not do this using Visual Force. So my 2nd best option was to create custom link or button on the contact page and when you click it, it brings up the related event history or task history depending which one was clicked.  So right now this is my problem where I have the VF Page and controller setup, but it;s not grabbing the contact id on the current page and showing it's related events.  I instantiated a variable to hold the current page and pass it to my soql statement but still haveing issues.   You probbably have a better way all toegther to do this. I've been working on this for months without a resolution

 

<apex:page controller="ActivityController">
<apex:pageBlock >
<apex:pageBlockTable value="{!Activities}" var="a">
<apex:column value="{!a.subject}"/>
<apex:column value="{!a.whoid}"/>
<apex:column value="{!a.whatid}"/>
<apex:column value="{!a.type}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

 

public class ActivityController 
{
    Public Event[] getActivities()
    {
      string currId =ApexPages.currentPage().getParameters().get('id');
       return [Select id, subject, what.id, who.id, type, activitydate from Event 
               where whoid=: currid and type= 'Client Meeting (Event)'];

    }



 
}
JimRaeJimRae

OK,

Now I have a better understanding of your goal.  What I would do is make the page a contact controller page, with an extension for your custom elements.


Here is the page layout:

 

 

<apex:page standardController="contact" extensions="ActivityController"> <apex:pageBlock title="Activity History" > <apex:pageBlockTable value="{!Activities}" var="a"> <apex:column value="{!a.activitydate}" /> <apex:column value="{!a.subject}"/> <apex:column value="{!a.whoid}"/> <apex:column value="{!a.whatid}"/> <apex:column value="{!a.type}"/> </apex:pageBlockTable> </apex:pageBlock> <apex:pageBlock title="Task History" > <apex:pageBlockTable value="{!Tasks}" var="t"> <apex:column value="{!t.activitydate}" /> <apex:column value="{!t.subject}"/> <apex:column value="{!t.whoid}"/> <apex:column value="{!t.whatid}"/> <apex:column value="{!t.type}"/> </apex:pageBlockTable> </apex:pageBlock> </apex:page>

 

And here is the controller (I took your extra filter out for testing purposes):

 

public class ActivityController { private final Contact cont; public ActivityController(ApexPages.StandardController controller) { this.cont = (Contact)controller.getRecord(); } Public Event[] getActivities(){ return [Select id, subject, what.id, who.id, type, activitydate from Event where whoid=:cont.id ]; } Public Task[] getTasks(){ return [Select id, subject, what.id, who.id, type, activitydate from Task where whoid=:cont.id ]; } }

 

By doing it this way, you could also add any other field from the contact to your VF page, if needed.  Also, this the only way to use this page from a button on the contact layout.

 

 From here, you would go to your setup, customize the contact object.  Go to the buttons and links, add a new custom button, make it a new Detail button, displayed in a new window with a content source of Visualforce page.  select the page you created and save.  Then edit your contact page layout to make the button visible, and you should be set.

 

 

 

bikla78bikla78

Jim thanks for your help on this and the extension logic make sense but here are some issues for our test results. We're almost there

 

1.  The whoid is not appearing under page for <apex:column value="{!a.whoid}"/>. So nothing is appearing under the name column

 

2.  In relation to #1 , the extension is pulling activities but it is pulling all the ones where the whoid is null in the event and task tables for some reason instead of using the whoid on the current page. It pulls the same null activities for every contact. So this.cont = (Contact)controller.getRecord(); does not seem to be executing correctly

 

3. If I get this to work, then that is great but is there a way to get these vf pages on the current contact page layout and replace the activity history standard page or do i have to create the entire contact page from sratch? I have feeling the answer is yes and that might take forever to code and the button might be suffcient

 

Thanks again I value your perspective. It's been a great leanring experience.

 

 

JimRaeJimRae

You are welcome.

Not sure why that  would be happening to you, maybe it is the way you are attaching the page to your contact layout?

If you are running the page without attaching it to the layout for testing purposes, you would need to manually add the contact id so it could be picked up by the test code, like this:

 

https://cs3.salesforce.com/apex/splithistorytest?id=003000000005xCoQAW

 

I think your #1 and #2 are both related to how you are accessing the page from your contact layout.

 

Regarding #3, there is no way to replace a related list or add your own custom related list on a object (unfortunately).  You have 2 options that I am aware of, one, you can create the button with the popup page, like we have discussed, your other option, would be to embed the page in the body of the layout directly. I would make a new section, at the bottom of the contact layout, with a single column, and then you can add the new page there.

 

You could try option 2 just to validate the code is working, since it will also pickup the contact record parent (of the VF) page.

bikla78bikla78

Jim,

 

Great news. I realized I orginally linked the page by placing the actualy URL since I had issues of the VF Page content source not showing up. I also decided to create 2 seperate sections on the contact page. 1 called Event History and 1 called Task History. I seperated our activity history page and extensions into 2 seperate VF page and emebbed into the new sections and IT WORKED!!! Very very cool.  

 

2 questions

 

1. Since event history and task history can get really long, how can I create

 this is like the standard activity histor
 
2. How do I test VF pages, do i just put in test methods into the extension like i do with APEX trigger classes?
 
Thanks again and very exciting. i included my code below so others can use this
 







public class TaskController {
    private final Contact cont;
    public TaskController(ApexPages.StandardController controller) {
        this.cont = (Contact)controller.getRecord();
    }
    Public Task[] getTasks(){
        return [Select id, subject, what.id, who.id, type, activitydate from Task
               where whoid=:cont.id ];
    }

}
   

<apex:page standardController="contact"   extensions="ActivityController">
<apex:pageBlock title="Event History" >
<apex:pageBlockTable value="{!Activities}" var="a">
<apex:column value="{!a.activitydate}" />
<apex:column value="{!a.subject}"/>
<apex:column value="{!a.whoid}"/>
<apex:column value="{!a.whatid}"/>
<apex:column value="{!a.type}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
                     



public class ActivityController {
    private final Contact cont;
    public ActivityController(ApexPages.StandardController controller) {
        this.cont = (Contact)controller.getRecord();
    }
    Public Event[] getActivities(){
        return [Select id, subject, what.id, who.id, type, activitydate from Event
               where whoid=:cont.id ];

    }


}

<apex:page standardController="contact"   extensions="TaskController">
<apex:pageBlock title="Task History" >
<apex:pageBlockTable value="{!Tasks}" var="t">
<apex:column value="{!t.activitydate}" />
<apex:column value="{!t.subject}"/>
<apex:column value="{!t.whoid}"/>
<apex:column value="{!t.whatid}"/>
<apex:column value="{!t.type}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
                       
 

 

Message Edited by bikla78 on 10-12-2009 12:31 PM
JimRaeJimRae

I don't think you will be able to emulate the "Show More" since you can't really change the size of the iframe the page is displayed in dynamically.  You could add a command link that opens a page version in a separate window for the "Go to List", you would need to build the page with whatever features you needed , things like pagination, "next" and "previous" links, etc.

 

To test the page and controller, what I usually do is create a separate testmethod, create reference to the page first, to make sure it exists.  Then you will need to instantiate the controller extension and test each of the methods. Since this is designed to be the child of another page, you will need to "put" the id of a test contact into the page reference so the extension can pick it up.

There is an example of this structure in the Visualforce developers guide (page 68).

 

bikla78bikla78

Got it. I will try that.

 

Also, When i logged in as a different user, they seem to see this inside the task history vf page instead of the actual tasks.I also know it;s not a administation security problem since they can see other people's tasks in the standard activity history page.

 

 

Insufficient Privileges
You do not have the level of access necessary to perform the operation you requested. Please contact the owner of the record or your administrator if access is necessary.




Internal Diagnostics:
You do not have sufficient privileges to access the page: /apex/TaskHistory
system.security.NoAccessException: You do not have sufficient privileges to access the page: /apex/TaskHistory
at core.apexpages.framework.ApexViewServlet$1.call(ApexViewServlet.java:319)
at core.apexpages.framework.ApexViewServlet$1.call(ApexViewServlet.java:280)
at core.apexpages.components.framework.context.NamespaceRunner.run(NamespaceRunner.java:98)
at core.apexpages.components.framework.context.NamespaceRunner.run(NamespaceRunner.java:76)
at core.apexpages.framework.ApexViewServlet.runLifecycle(ApexViewServlet.java:280)
at core.apexpages.framework.ApexViewServlet.handlePage(ApexViewServlet.java:232)
at common.request.servlet.BaseApplicationServlet.serviceInternal(BaseApplicationServlet.java:116)
at common.request.servlet.BaseApplicationServlet.doService(BaseApplicationServlet.java:60)
at common.request.servlet.ProtectedHttpServlet.service(ProtectedHttpServlet.java:28)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:91)
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:103)
at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178)
at core.apexpages.framework.ApexViewXMLFilter.doXmlFilter(ApexViewXMLFilter.java:25)
at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290)
at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:390)
at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:517)
at core.apexpages.framework.ApexViewFilter.doFilter(ApexViewFilter.java:23)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.StatsOnlyFilter.doFilter(StatsOnlyFilter.java:80)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.PostGzipFilter.doFilter(PostGzipFilter.java:28)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at com.caucho.filters.GzipFilter.doFilter(GzipFilter.java:169)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.VisualforceDomainRedirectFilter.doFilter(VisualforceDomainRedirectFilter.java:105)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at core.dns.filter.CustomDomainMappingFilter.doFilter(CustomDomainMappingFilter.java:177)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at core.dns.filter.BandwidthMeterFilter.doFilter(BandwidthMeterFilter.java:87)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.BasePreGzipFilter.doFilter(BasePreGzipFilter.java:107)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.RedirectFilter.doFilter(RedirectFilter.java:116)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.XssFilterBase.doFilter(XssFilterBase.java:33)
at system.filter.XssFilter.doFilter(XssFilter.java:140)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.ModifiableParameterFilter.doFilter(ModifiableParameterFilter.java:29)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.RequestEncodingFilter.doFilter(RequestEncodingFilter.java:63)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.InstanceRedirectFilter.doFilter(InstanceRedirectFilter.java:486)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at routing.filter.RemoteAddrFilterBase.doFilter(RemoteAddrFilterBase.java:70)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.filter.LegacyJSPFilter.doFilter(LegacyJSPFilter.java:199)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at routing.filter.LoadBalancerFilter.doFilter(LoadBalancerFilter.java:65)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at system.context.ContextReleaseFilter.doFilter(ContextReleaseFilter.java:69)
at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:187)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:266)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:270)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:678)
at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:721)
at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:643)
at java.lang.Thread.run(Thread.java:619)

 

JimRaeJimRae

Did you set security on the page and controller to all other users to access it?

Go to Setup | Develop | Apex Classes

Select your class by the name, you will see a button called "Security" that allows you to specify which profiles can access the class.

 

 For the pages, Go to  Setup | Develop | Pages

 

You will see a "Security" link next to each page, again this allows you to specify which profiles can access the page.

 

That would be my guess as to the issue.

This was selected as the best answer
bikla78bikla78

When I am ready to deploy this in production, i only need to write test methods for the controller and create the apex page directly in production ? Looks like the VF page doesn't need any test methods since it is the presentation layer which calls the controller class..is this correct? thanks again for all your help jim

 

 

This is my first VF Page deployment.

Message Edited by bikla78 on 10-29-2009 01:32 AM
JimRaeJimRae

You should set the test in the context of the page, to make sure that the page exists, and to exercise all of the standard controller methods.  If I remember correctly, you want this page to extend something from the standard contact record, so you need to emulate how the page will get the contact id to retreive the data from.  This isn't tested, but should give you a start.  You will need to create a second test for your Task page and controller.  They could both be in the same testclass.

 

 

public class testMyPage { static testMethod void myPage_Test(){ //Test coverage for the myActivityHistory visualforce page PageReference pageRef = Page.myActivityHistory; Test.setCurrentPageReference(pageRef); //create test Account Account newAccount = new Account (name='XYZ Organization'); insert newAccount; //create test Opportunity Opportunity newOpp = new Opportunity(name='Test Opp', closedate=date.newinstance(2010,03,31), Accountid=newAccount.id); insert newOpp; //create test contact Contact myContact = new Contact (FirstName='Joe', LastName='Schmoe', Accountid=:newAccount.id); insert myContact; //create test events Event myEvent = new Event(Subject='Test Subject', activitydate = Date.newinstance(2009,12,25), whoid=myContact.id, whatid=newOpp.id, type='Sales Event'); insert myEvent; Event myEvent2 = new Event(Subject='Test Subject Two', activitydate = Date.newinstance(20010,02,25), whoid=myContact.id, whatid=newOpp.id, type='Sales Event'); insert myEvent2; ApexPages.StandardController sc = new ApexPages.standardController(myContact); // create an instance of the controller ActivityController myPageCon = new ActivityController(sc); //try calling methods/properties of the controller in all possible scenarios // to get the best coverage. List<Event> myActivities = myPageCon.getActivities(); //should return the 2 activities we created system.assert(myActivities.size()==2); } }

 

 

bikla78bikla78

Thanks Jim but what I am confused on is do I have to deploy the vf page below  into to production with the test methods or can I just simply create the page into production(pretty much a copy and paste)- it looks like I can create VF pages directly in production without testing them.  However, I realize the apex controllers need to be tested and deployed.

 

<apex:page standardController="contact"   extensions="AllActivityController">
<apex:pageBlock title="Event History" >
<apex:pageBlockTable value="{!Activities}" var="a">
<apex:column value="{!a.activitydate}" />
<apex:column value="{!a.subject}"/>
<apex:column value="{!a.whoid}"/>
<apex:column value="{!a.whatid}"/>
<apex:column value="{!a.type}"/>
</apex:pageBlockTable>
</apex:pageBlock>
<apex:pageBlock title="Task History" >
<apex:pageBlockTable value="{!Tasks}" var="t">
<apex:column value="{!t.activitydate}" />
<apex:column value="{!t.subject}"/>
<apex:column value="{!t.whoid}"/>
<apex:column value="{!t.whatid}"/>
<apex:column value="{!t.type}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>

 

JimRaeJimRae
You won't be able to save the page in production until the controller exists.  I would recommend, from a best practice standpoint, that you deploy the testclass, controller and page all together at the same time.
bikla78bikla78

Ok. I will do that.

 

Question on page. Is there a way I can limit how many records are showing in each section. Is there  vf page tag that allows only 6 records per page and be able to click expand to see more?

JimRaeJimRae
You can do that by implementing a standardsetcontroller in your custom controller.  I understand there is a way to set the page size (number of records to display) as well.  I have not done this myself, so I don't have much advice, except check the forums for examples.
TheBootTheBoot

Thanks for sharing the code for this here.  I am looking to do something like this.  Would this still work as a pop up window?  I would like to display all the completed activites in a seperate window for either a Lead or a Contact so that when a rep goes to call them, they canhave their Activity history right there on screen.

 

Last time I checked you can't do this in Console, which would be the easy way..but this is a nice solution.

 

Im a bit scared about the whole test code thing.  I have never done that before. 

JimRaeJimRae
I don't see why you couldn't leverage this code to create a new page that you popped up for the user.  There are lots of samples on the boards about creating different types of pop ups. You could combine one of them with the code here to get what you are looking for.