For example, consider the following page. This outputs the details of up to 10 contacts associated with an account:
<apex:page standardController="Account" extensions="ParamBlogController"> <apex:outputPanel id="all"> <apex:form> <apex:pageBlock title="Account Detail"> <apex:pageBlockSection title="Account"> <apex:outputField value="{!Account.Name}"/> <apex:outputField value="{!Account.Description}"/> </apex:pageBlockSection> <apex:pageBlockSection title="Contacts" columns="1"> <apex:pageBlockTable value="{!conts}" var="cont" rows="10"> <apex:column value="{!cont.Id}"/> <apex:column value="{!cont.Name}"/> <apex:column value="{!cont.Email}"/> <apex:column value="{!cont.Phone}"/> </apex:pageBlockTable> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:outputPanel> </apex:page>
The controller is as follows - note that I retrieve the contacts and store them in a list rather than relying on the Account.Contacts related list - there is a good reason for this and it will (hopefully) become clear later on:
public class ParamBlogController { private ApexPages.StandardController stdCtrl {get; set;} public List<Contact> conts {get; set;} public ParamBlogController(ApexPages.StandardController std) { stdCtrl=std; setupContacts(); } private void setupContacts() { conts=[select id, Name, Email, Phone from Contact where AccountId=:stdCtrl.getId()]; } }
The output of the page is shown below:
Next up I want to add a column that allows various actions to be performed on the particular contact instance. Its tempting to think that I can just add the following to the markup (assuming I have an appropriate method in the controller) and all will be well:
<apex:column headerValue="Action"> <apex:commandButton value="Del" action="{!delCont(cont.id)}"/> </apex:column>
However, this refuses to compile with an error that delCont is an unknown function. As controller action methods can't take parameters in this way, the compiler assumes that this is a formula function, but no function with that name exists, hence the error.
So, how can we pass the id of the contact to the controller? The answer is straightforward, but requires a slight mindshift.
The <apex:param> standard component allows parameters to be defined for a parent component, which can be assigned to a controller property. I can therefore change my markup to the following to specify the parameter:
<apex:commandButton value="Del" action="{!delCont}" rerender="all"> <apex:param name="contIdParam" value="{!cont.id}" assignTo="{!contIdChosen}"/> </apex:commandButton>
Note the rerender attribute of the commandbutton - if this attribute is not present, the parameter does not get sent back to the controller. I simply have an outputpanel around the entire page contents.
I then add the following property to my controller:
public String contIdChosen {get; set;}
The key to this is the behaviour when the button is clicked - the id of the contact instance is assigned to my controller property before the action method is invoked. Thus the method that is actually carrying out the delete can simply access the contIdChosen property secure in the knowledge that it will contain the id of the contact associated with the button:
public PageReference delCont() { Contact toDel=new Contact(id=contIdChosen); delete todel; setupContacts(); return null; }
The fact that I have to rerender in order to get the parameter passing to work is the reason why I maintain the list of Contacts independent of the Account record from the standard controller - I can't make the browser refresh the page and thus rebuild the related contacts from scratch, so I have to rebuild the list server side.
This comment has been removed by the author.
ReplyDeleteThank you. This post was of great help.
ReplyDeleteThanks for this explanation, Explained what I couldn't find in the tutorials.
ReplyDeleteSo the contIdChosen variable's scope isn't limited to the function you've called, correct?
ReplyDeleteCorrect. Its a class level property of the controller and accessible to any methods in the class.
DeleteI have used exactly the same code for deletion of a row in the pageblocktable, but I get the error that the variable toDelIdent does not exist. Why is it so ? I have passed it the same way using apex:param in the page.
ReplyDeleteThis usually means that the property can't be found. Is toDelIdent public with a public getter and setter?
DeleteI am getting an Error: Unknown property 'AccountStandardController.conts'
ReplyDeleteIn the pageblocktable.,,
when I
Please find this out?
That sounds like the extension controller hasn't been picked up properly, or the 'conts' property hasn't been correctly declared.
DeleteThis comment has been removed by the author.
ReplyDeleteHow would this work when trying to update a (boolean) variable in a wrapper class? I have a list of wrapper classes being displayed in a pageblocktable (data coming from wrapperClass.Product__c if that makes sense) . In a column I have a button where the use can click a commandButton to show List of OTHER records in a nested pageblocktable, the list is in the same wrapper class (wrapperClass.List(Pricing__c)). The control over each display of the nested table is done using a third item in the wrapper class wrapperClass.showPricing (boolean) which is what the rendered attribute on the nested table is set to.
ReplyDeleteOn click I need to update the showPricing variable to "true" for THAT SPECIFIC wrapperClass. Does that make sense? Do you need more info?
Also, as a bonus, is there a way for the update to happen 'smoothly', i.e. the page doesn't reload and the user is brought back to the top of the page, etc.
Thanks,
Jeremy Stender
To clarify, the updating of the variable to 'true' would cause the nested table of "Pricing__c" records to display. The display of these is what I want to happen 'smoothly'.
DeleteDon't you hate it when you ask a question and then figure it out immediately after?
DeleteI was able to do this by using the above and putting the path to the boolean variable in the assignto="", using the pageblocktable's variable for the current wrapperClass.
Thanks for the help!
I have an "apex:inputFile" on the same page, so using rerender="all" causes the following error:
ReplyDelete"apex:inputFile can not be used in conjunction with an action component, apex:commandButton or apex:commandLink that specifies a rerender or oncomplete attribute."
Any way around this problem? Other than getting rid of the inputFile.
The way around this is to have a hidden input field and set the value of the parameter into that prior to executing the action method. I've been asked this a few times recently so I think I'll write another blog post explaining how it works. Stay tuned.
DeleteI'd be interested in hearing what you do in this situation as well.
Deleteyou have my eternal gratitude. your graciousness is appreciated
ReplyDeleteHow to create horizontal scrollbar in the inline visualforce page
ReplyDeleteHi Bob,
ReplyDeleteI need to get values form vf page what ever i entered on vf component example if i enter name="xxx" i should get "xxx" value to my controller.
That sounds like regular visualforce forms. Have you looked at the developer's guide?
DeleteThis comment has been removed by the author.
ReplyDeleteHi Bob,
ReplyDeletefirst of all, thanks you for what you are doing - I am relatively new to Salesforce and your posts have helped me on numerous occasion.
My question is following - in the post above you say:
"Note the rerender attribute of the commandbutton - if this attribute is not present, the parameter does not get sent back to the controller."
I'm having trouble wrapping my mind around it. From what I understand about rerender attribute it is used to indicate page elements that should be refreshed upon AJAX request. So why does pressence/absence of this attribute affect parameters being passed to the controller? I would really appreciate if you could shed some light on this matter.
Cheers
Ivan
Certainly - its a bug in Visualforce where if you don't use a rerender attribute, the parameter doesn't get passed to the controller.
DeleteMy fellow MVP Wes Nolte wrote this up on his blog at:
http://th3silverlining.com/2009/06/12/salesforce-bugs-you/
I have a List (in an Apex extension) of a custom object called Question Assignments (QA) populated via a SOQL query - we use this to dynamically populate the question text on a visualforce page.
ReplyDeleteIn this query, I am also pulling back the Question ID, which we will need to go execute a separate query (at least the way I'm attempting at this point) to pull back a list of select options used in a selectRadio component.
I have been attempting to use the apex:param option (currently tied to an output text field used as a label for the radio button group), but have failed at doing this just about every way I've found online.
Is what I'm trying to do even possible? Any pointers would be appreciated! Thanks!
Hi Bob Buzzard,
ReplyDeleteUsing wrapper class i displayed all custom objects in my organization through custom controller and i gave delete command link of each object.when i click delete command link,how to delete custom object from database?
please help me............
Used this today! Thanks, Bob!
ReplyDeleteHi Bob!! I have to redirect from one Page to other and pass a parameter to other page. Is it possible to send the value without displaying it in URL?
ReplyDeleteAlso, can this be done at the page level as I am using an anchor tag to redirect and don't want to call the controller method
I have requirement like this if a customer enter his email id and phone number then only then the valid customer gets popped...
ReplyDeletehi, i want create 2 visualforce page with a controller using custom object.In the first page i want to select the one record and pass it's id to another visual force page which will show it's details using query string.
ReplyDeleteThis post shows how to pull parameters from the query string and process them in a controller:
Deletehttp://bobbuzzard.blogspot.co.uk/2011/06/execute-custom-search-when-opening-page.html
Hi Bob, thank you very much for this example, it is very useful! I would also like to pass the parameter to a second page, however I am using one controller for both pages, as I am building a wizard. Do you know if there is a way to pass the parameter like in your example but keeping the single controller? In my code the redirect does not work because of the bug that requires the button rerendering which then breaks the page redirect. Thank you!
DeleteHi Bob,
ReplyDeleteI have a method in my apex class that takes a string (a destination) and gives me the Average Price for this destination.
So, what I want to do, is create a paragraph in the visualforce page to have something like this:
Destination: getAverageDestination(destination) in the paragraph.
where getAverageDestination is the name of the method in my apex class.
So my question is how can I call the method getAverageDestination in my visualforce page and pass the attribute destination to this method?
Thanks a lot for your help.
Thanks a lot Bob..It resolve my issue.
ReplyDeleteThanks a ton
Could you use this method in a PageBlockTable returning a list, to filter the items retuned in the list?
ReplyDeleteHi Bob,
ReplyDeleteHow to pass id of lookup field from vf page to controller in lightning
Thank you Bob. You really saved my bacon with this article.
ReplyDeletehow can i select multiple record and delete them once??
ReplyDeleteThe fact that this blog post is still relevant and fixing issues in 2022 is amazing. Thanks for this Bruno, you've saved me after hours of articles searches !
ReplyDelete