Lets assume I have a Page code:
<apex:pageBlockTable value="{!allContacts}" var="c" >
<apex:column value="{!c.id}" headervalue="ID"/>
<apex:column value="{!c.FirstName}" headervalue="First Name"/>
<apex:column value="{!c.LastName}" headervalue="Last Name"/>
<apex:column value="{!c.Title}" headervalue="Title"/>
<apex:column value="{!c.Company}" headervalue="Company"/>
<apex:column>
<apex:commandButton action="{!addToRecruits}" value="Recruit">
<apex:param assignTo="{!leadID}" name="leadID" value="{!c.id}"/>
</apex:commandButton>
</apex:column>
</apex:pageBlockTable>
And relevant controller :
public String leadID { get; set; }
public PageReference addToRecruits() {
System.debug('LeadID is: ' + leadID);
List<Lead> potentialCandidate = [SELECT id, FirstName, lastName, Title, Company FROM Lead WHERE id = :leadID];
delete potentialCandidate;
return null;
}
It seems that I can NOT pass leadID to addToRecruits() method. Do you have any idea why is so?
UPDATE:
I could manage to solve it. Instead of querying using SOQL, I approached with this style:
public String leadID { get; set; }
public PageReference addToRecruits() {
Lead candidate=new Lead(id=leadID);
....
}
Looks like the infamous platform bug? where apex:param values are not always send to the controller with apex:commandButton (though they are send with apex:commandLink).
A simple overview of the issue and possible workarounds are summarised by Jeff Douglas here: http://blog.jeffdouglas.com/2010/03/04/passing-parameters-with-a-commandbutton/
Add "rerender" attribute to apex:commandButton and its will start working - Something like
<apex:commandButton rerender="myForm" action="{!addToRecruits}" value="Recruit">
There is one way to pass parameter to controller but it will use commandLink also. I mean we need to use
command link and command button
Eg:
<apex:commandLink action="{!applyNow}" id="applybuttonLink" style="text-decoration:none">
<apex:commandButton value="Apply now"/>
<apex:param name="passId" assignTo="{!passId}" value="{!Vac.id}"/>
</apex:commandLink>
Controller:
public String vacancyId{get;set;}
Related
I'm trying to display values of a List<Map<String, Object>> in a Visualforce page by using apex:pageBlockTable.
I'm stuck on what to put in apex:outputField value like below.
Is there any way that this can be made to work? The number of Map<String, Object> is variable.
apex:
String theJsonString = '[{"id":1, "name":"Abc_SS", "description":"Abc", "address":"Abc"}, {"id":2, "name":"sales", "description":"sales", "address":"Abc"}]';
Object theJsonObject = JSON.deserializeUntyped(theJsonString);
List<Object> theJsonList = (List<Object>) theJsonObject;
List<Map<String, Object>> theJsonMapList = new List<Map<String, Object>>();
for (Object obj : theJsonList) {
theJsonMapList.add((Map<String, Object>) obj);
}
visualforce page:
<apex:pageBlockTable value = "{!theJsonMapList}" var="al">
<apex:column headerValue="id">
<apex:outputField value=??>
</apex:column>
<apex:column headerValue="name">
<apex:outputField value=??>
</apex:column>
<apex:column headerValue="discription">
<apex:outputField value=??>
</apex:column>
<apex:column headerValue="address">
<apex:outputField value=??>
</apex:column>
</apex:pageBlockTable>
You can't use outputField at all because it's "magic". It works only with real database sobjects (Account, Contact, custom objects...) because it then can read what's the field type and how to properly display it (lookup - make a link. Date - format. etc)
Your data is unrelated, bunch of generic Objects so you're limited to outputText etc.
This should work nicely:
public class Stack73773910 {
public List<Map<String, Object>> getData(){
String theJsonString = '[{"id":1, "name":"Abc_SS", "description":"Abc", "address":"Abc"}, {"id":2, "name":"sales", "description":"sales", "address":"Abc"}]';
Object theJsonObject = JSON.deserializeUntyped(theJsonString);
List<Object> theJsonList = (List<Object>) theJsonObject;
List<Map<String, Object>> theJsonMapList = new List<Map<String, Object>>();
for (Object obj : theJsonList) {
theJsonMapList.add((Map<String, Object>) obj);
}
return theJsonMapList;
}
}
<apex:page controller="Stack73773910">
<apex:pageBlock>
<apex:pageBlockTable value = "{!data}" var="al">
<apex:column headerValue="id">
<apex:outputText value="{!al['id']}"/>
</apex:column>
<apex:column headerValue="name">
<apex:outputText value="{!al['name']}"/>
</apex:column>
<apex:column headerValue="description" value="{!al['description']}"/> <!-- you can cheat if you don't need special output like number / date / checkbox formatting -->
<apex:column headerValue="address" value="{!al['address']}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>
In the long run... as your JSON grows more complex and maybe you start using it in Apex for more things, not just displaying it... You'll grow angry with all the casting to Date , Boolean, String, Decimal you'll have to do to access the data. There are tools to help make you a helper class to hold this data as a proper object, not a stupid Map<String, Object>.
Have a look at https://json2apex.herokuapp.com/. It will let you have a List<MyWrapper> - parsing it should be similar complexity to what you have now but then in Visualforce you'll be back to old, simple {!al.name}
I want to add a custom VF component to display the batch job details in a pageblock table. However my component aint saving, it says: Error Error: Read only property 'c:batchDetailsComponent.BatchJobDetails'
Please help.
This is the visualforce component:
<apex:component controller="BatchOpportunityDetailsExtension">
<apex:attribute name="batchJob" type="List" assignTo="{!BatchJobDetails}" description="" />
<apex:form >
<apex:pageBlock>
<apex:pageblockTable value="{!batchJob}" var="batch">
<apex:column value="{!batch.CompletedDate}"/>
<apex:column value="{!batch.JobItemsProcessed}"/>
<apex:column value="{!batch.NumberOfErrors}"/>
</apex:pageblockTable>
</apex:pageBlock>
</apex:form>
</apex:component>
VF Page:
<apex:page standardController="Opportunity_Scheduled_Information__c"
extensions="BatchOpportunityDetailsExtension">
<c:oppScheduleComponent componentValue="{!batchJob}"/>
</apex:page>
Controller:
public class BatchOpportunityDetailsExtension {
public List<AsyncApexJob> batchJobDetails = new List<AsyncApexJob>();
public Opportunity_Scheduled_Information__c pageController {get;set;}
public BatchOpportunityDetailsExtension() {}
public BatchOpportunityDetailsExtension(ApexPages.StandardController controller) {
controller.addFields(new List<String>{'Total_Amount__c', 'Number_of_Opportunities__c'});
pageController = (Opportunity_Scheduled_Information__c)controller.getRecord();
BatchJobDetails = [ SELECT id,ApexClassID,CompletedDate,JobType,JobItemsProcessed,NumberOfErrors,MethodName,Status,ExtendedStatus,TotalJobItems FROM AsyncApexJob WHERE ApexClassId='01p7F000000bKIlQAM' LIMIT 50] ;
}
public List<AsyncApexJob> getBatchJobDetails()
{
return BatchJobDetails ;
}
}
You need to set the access for your component to global.
Like this: <apex:component access="global" controller="BatchOpportunityDetailsExtension">
I have a visualforce page that has a picklist called Topic and sometimes I will need to select one of the picklist options upon page load (meaning the Topic will be passed on from another page and will need to be selected upon loading the page for the first time). I'm not sure how to do this? I'm posting part of the Visualforce page that handles topic selection and the Controller code that below. Any help would be appreciated.Thanks.
Visualforce page:
<!---------------------------------- Select Topic ----------------------------------------------------->
<apex:pageblockSection title="Select the Topic" >
<apex:selectList value="{!topic}" size="1">
<apex:outputlabel for="Topic" value="Pick a Topic :" ></apex:outputlabel>
<apex:selectOptions id="topic" value="{!Topics}"/>
<apex:actionSupport action="{!populateParameters}" reRender="parametersSection,querySection" event="onchange"/>
</apex:selectList>
</apex:pageblockSection>
<!---------------------------------- End of Select Topic ---------------------------->
<!---------------------------------- Parameters for Topic ----------------------------------------------------->
<apex:pageblockSection id="parametersSection" title="Input Parameters">
<apex:repeat value="{!topicpParamWrapperList}" var="params">
<apex:outputPanel >
<apex:outputlabel value="{!params.parameter.Name}" ></apex:outputlabel>
<apex:inputfield value="{!params.parameter.inputValue__c}" rendered="{!params.renderAsText}">
<apex:actionsupport action="{!placeValuesInQuery}" reRender="querySection,splunUrlLink" event="onchange"/>
</apex:inputfield>
<apex:inputfield value="{!params.parameter.DateTimeValueHolder__c}" rendered="{!params.renderAsDate}">
<apex:actionsupport action="{!placeValuesInQuery}" reRender="querySection,splunUrlLink" event="onchange"/>
</apex:inputfield>
</apex:outputPanel>
</apex:repeat>
</apex:pageblockSection>
<!---------------------------------- End of Parameters for Topic ----------------------------------------------------->
Apex Controller
public List < topicpParamWrapper > topicpParamWrapperList {
get;
set;
} {
topicpParamWrapperList = new List < topicpParamWrapper >();
}
public void populateParameters()
{
if(!topicpParamWrapperList.isEmpty())
{
topicpParamWrapperList.clear();
}
if(topic!='' && topic!=Null)
{
for(Query_Parameter__c qParam :[select id, Parameters__r.Variable_Name__c, Parameters__r.Type__c,Parameters__r.Name from Query_Parameter__c where Topics__c=:topic])
{
Parameters__c param = new Parameters__c();
param.Name =qParam.Parameters__r.Name ;
param.type__c = qParam.Parameters__r.type__c;
param.Variable_Name__c=qParam.Parameters__r.Variable_Name__c;
topicpParamWrapperList.add(new topicpParamWrapper(param));
}
getQueryToRun();
}
}
public void getqueryToRun(){
if(mapTopics.containsKey(topic))
{
this.queryToRun =mapTopics.get(topic).query__c;
this.queryMain=mapTopics.get(topic).query__c;
}
}
public List < topicpParamWrapper > paramList {
get;
set;
} {
paramList = new List <topicpParamWrapper>();
}
All you really have to do is to set the topic to some initial value in the constructor (the special function that has name identical to class' name). You set it to some value and then it'll be rendered properly in visualforce (assuming same value is one of the selectable options!).
You have omitted the constructor or <apex:page> tag so we don't know how you're navigating to that page. But probably easiest for you would be to pass the topic in the URL. So if you access the page like that:
/apex/MyPage?topic=Something, something
then in the constructor you could do this:
topic = ApexPages.currentPage().getParameters().get('topic');
(the name of the URL parameter doesn't have to be same as the variable name but it makes sense to have them at least similar)
You can read more about getParameters()
If there is risk that your topic will contain &, spaces etc you probably should URLENCODE it when building the link.
I want to display the AggregateResult on my Visualforce page but it is generating the following error " Invalid field Email for SObject AggregateResult"
Below is my code:
public with sharing class searchDuplicate {
public AggregateResult[] con{get;set;}
public searchDuplicate()
{
find();
}
public void find(){
con = [select Email from Contact group by Email having count(Email) > 1];
System.debug(con);
}
}
Below is my visualforce page code:
<apex:page controller="searchDuplicate">
<apex:pageBlock title="Searching for Duplicate Contacts Record">
</apex:pageBlock>
<apex:pageBlock title="Contacts">
<apex:dataTable value="{!con}" var="c" border="2" cellspacing="5" cellpadding="5">
<apex:column headerValue="Email" value="{!c['Email']}" />
</apex:dataTable>
</apex:pageBlock>
</apex:page>
kindly Make a correction if possible
public with sharing class searchDuplicate {
public list <con> conList{get;set;}
public class con{
public string Email {get;set;}
public con( string email){
this.Email = email;
}
}
public searchDuplicate()
{
find();
}
public void find(){
conList = new list <con>();
for( AggregateResult ar : [select Email from Contact group by Email having count(Email) > 1];){ conList.add(new con(string.valueOf(ar.get('Email')))) }
}
}
Aggregate results (and their fields/columns) come as generic Objects, not sObjects. Therefore there's no obj.get('somefieldname') you can call on them.
Your best option might be to make a helper class that has String email; Integer count; fields and loop through the query results populating a list of objects of this helper class.
You could also use Map<String, Integer> but that'd come to VF as not sorted alphabetically.
See https://salesforce.stackexchange.com/questions/7412/count-a-grouped-by-soql if you need a code sample.
Although the other answers are correct in solving your problem, what you have is actually a bug in SalesForce.
The way to resolve this without creating a custom object is to separate the into two - The "headerValue" and "value" both being set cause this error.
You want to change it to this:
<apex:dataTable value="{!con}" var="c" border="2" cellspacing="5" cellpadding="5">
<apex:column headerValue="Email" >
<apex:outputText>{!c['Email']}</apex:outputText>
</apex:column>
</apex:dataTable>
Thanks,
Michael
I have the following page that shows documents from database, what I'm trying to accomplish is to make this page refresh or update automatically if a new document is added in the database. Is there a way I can use AJAX or pulling or something in my controller or page to accomplish that ?
Page:
<apex:pageBlockTable value="{!docs}" var="d" rendered="{!NOT(ISNULL(docs))}" Title="Documents">
<apex:column headerValue="Name">
<apex:outputText value="{!d.Name}"/>
</apex:column>
</apex:pageBlockTable>
Contoller
public List<FTPAttachment__c> getDocs()
{
docs= [Select Name from FTPAttachment__c where Case__c = :cse.id];
return docs;
}
Sounds like you're looking for the <apex:actionPoller> tag:
<apex:actionPoller action="{!refreshDocs}" rerender="docsTable" interval="5" />
<apex:pageBlockTable id="docsTable" value="{!docs}" var="d" rendered="{!NOT(ISNULL(docs))}" Title="Documents">
<apex:column headerValue="Name">
<apex:outputText value="{!d.Name}"/>
</apex:column>
</apex:pageBlockTable>
You could have the refreshDocs() method explicitly repopulate the docs list, but since you're already doing that in your getter (which will be called when the table is re-rendered), this method can just return without doing anything special:
public List<FTPAttachment__c> getDocs() {
return [Select Name from FTPAttachment__c where Case__c = :cse.id];
}
public PageReference refreshDocs() {
return null;
}
Alternatively you could use the streaming api.
http://www.salesforce.com/us/developer/docs/api_streaming/index.htm