Populate select list with contacts - salesforce

I want to use a apex:selectList to populate contacts. The problem is that it gives an error
Collection size 3,403 exceeds maximum size of 1,000
This is because i have 3403 contacts, and Vf has limitation on the collections in the VF page.
I want to limit the inital set of contacts to <1000, and as the user starts typing in the characters i would want to query the contacts. For ex if the user types in Ji i want to query the contacts to retrieve records starting with JI.
Is this possible to do?
<apex:selectlist id="ClientsSearch" value="{!Appointment.Client__c}"
size="1" required="true" rendered="{!NOT (SearchMode)}">
<apex:selectOptions value="{!Clients}" />
</apex:selectlist>
public List<SelectOption> getClients() {
List<SelectOption> options = new List<SelectOption>();
List<Contact> Clients = [Select id, Name From Contact order by Name];
options.add(new SelectOption('0001', '--Select--'));
for(Contact c : Clients ){
options.add(new SelectOption(c.id, c.Name));
}
return options;
}

You can use wild cards in your query to do this — so you'll want to add an <apex:inputText> element in your page to allow them to enter a search term, which writes to a string variable in the controller. Then add a search button to run the query and re-render the list with the new list of contacts.
The important parts of the controller will look something like this:
public string SearchTerm {get; set;}
public list<ContacT> Contacts {get; set;}
public Pagereference SearchContacts()
{
// etc.
Contacts = [select Id, Name from Contact where name like : '%' + SearchTerm + '%' order by name limit 1000];
// populate list here
return null;
}
You could perform the search using an action function and firing it from the onChange event of the input field but having a button to do the search will make the whole thing more response (IMO) from the user's point of view.
Note: I wrote this code on the fly, it may be that you can't just concat '%' with the search term in this manner or maybe that you don't even need to when querying directly. Usually in these cases I've had to utilise dynamic SOQL due to other requirements, where you build up the query in a string:
strQuery = 'select id from contact where name like \'%' +
String.escapeSingleQuotes(SearchTerm) + '%\' order by name';
for(Contact sContact : Database.query(strQuery) ...

There are a few options to get the functionality you'd like. It depends on how complicated of a solution you'd like, but there is always a solution.
You may want to consider using jQuery and SOSL (Search Language) in a controller. Here's an example of jQuery autocomplete with the Ajax API in Salesforce. Click the link below:
http://matthewkeefe-developer-edition.na8.force.com/jQueryAutocompleteWithAjaxAPI
Also, check out Tehnrd's post "Super Cool Advanced Lookup Component" for another option.

Related

Visualforce page not rendering values from controller

Need your inputs in a scenario I am currently stuck in. Here are the details. Appreciate your time and all your inputs.
currently I am able to see the values retrieved in controller but they are not being displayed on visualforce page.
Requirement: I need to email bulk of selected contacts. When there is no email to selected contacts, we are required to populate the name of contacts on UI who do not have the email. I am able to accomplish first part of requirement but stuck on displaying contact names on visual force page .
List button : BulkEmailTest which calls firstVF visual force page.
firstVF code:
<apex:page standardController="Contact" extensions="FirstController" recordSetVar="listRecs"
action="{!send}">
Emails are being sent!
<script> window.history.back();
</script>
</apex:page>
FirstController code: for simplified code, I have edited snippet for contacts with email as our priority is only related to contacts with no email.
public with sharing class FirstController
{
public List<Contact> noEmail {get;set;}
public Contact contact;
public List<Contact> allcontact {get; set;}
Id test;
public Contact getAllContact() {
return contact;
}
ApexPages.StandardSetController setCon;
ApexPages.StandardController setCon1;
public static Boolean err{get;set;}
public FirstController(ApexPages.StandardController controller)
{
setCon1 = controller;
}
public FirstController(ApexPages.StandardSetController controller)
{
setCon = controller;
}
public PageReference cancel()
{
return null;
}
public FirstController()
{
}
public PageReference send()
{
noEmail = new List<Contact>();
set<id> ids = new set<id>();
for(Integer i=0;i<setCon.getSelected().size();i++){
ids.add(setCon.getSelected()[i].id);
}
if(ids.size() == 0){
err = true;
return null;
}
List<Contact> allcontact = [select Email, Name, firstName , LastName from Contact where Id IN :ids];
for(Contact current : allcontact)
{
system.debug(current);
if (current.Email!= null)
{
PageReference pdf = Page.pdfTest;
pdf.getParameters().put('id',(String)current.id);
system.debug('id is :'+current.id);
pdf.setRedirect(true);
return pdf;
}
else //No email
{
system.debug('in else current'+current );
noEmail.add(current);
// noEmail.add(current);
system.debug('in else noemail'+noEmail );
}//e
}
if(noEmail.size()>0 ) {
PageReference pdf1 = Page.NoEmailVF;
pdf1.getParameters().put('Name', String.valueOf(noEmail));
system.debug('pring noEmail' +noEmail);
pdf1.setRedirect(false);
return pdf1;
}
return null;
}
}
NoEmailVF visual force page code
<apex:page controller="FirstController">
<b> Emails are not sent to below contacts :
<table border="1">
<tr>
<th>Name</th>
</tr>
<apex:repeat var="cx" value="{!allcontact}" rendered="true">
<tr>
<td>{!cx.name}</td>
</tr>
</apex:repeat>
</table>
<p> Please note that emails are not sent to selected Donors only when
they did not make any donation for that year or if they do not have email address listed. </p>
<p>If you still wish to retrieve donations made in this year, then you may use "Hard Copy" button listed on the Donor record to have the data printed. </p>
</b>
<apex:form >
<apex:commandButton action="{!cancel}" value="Back" immediate="true"/>.
</apex:form>
</apex:page>
It's bit messy. I think I know why it doesn't work but I'm also going to give you few tips how to clean it up.
I don't think you need 2 separate pages. You could do it on 1 page. I'm not even sure what were you trying to accomplish. Should the user be moved to previous page (some listview button I guess? Wherever history.back() takes them). Or to Page.NoEmailVF. (and there's even Page.pdfTest thrown into the mix ;))
If you're sure you need multiple pages - here's how you can transfer "state" of the controller across pages. It should work automatically as long as they share same controller (or extension), no need to pass anything via url: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_quick_start_wizard.htm
Your constructors don't do much. They save the references to standard(set)controller but they don't run any queries. Contacts aren't queried until the send() method.
You're hoping to pass the noEmail parameter with String.valueOf(List<Contact>). It's... uh.. it probably does something but after redirect you don't read anything. The NoEmailVF page has just <apex:page controller=... (not an extension) so the FirstController() (the one without any parameters) is called. And it has empty body! It completely ignores what was passed via url. It probably could read what you passed using ApexPages.currentPage().getParameters().get('Name') but then honestly no idea what you can do to create real list of contacts out of such string. Messy. You probably could do some JSON.serialize and then deserialize but I don't like the whole idea.
And last but not least - calling page action is evil, unexpected for the user and against salesforce security best practices. Pls check my old answer https://salesforce.stackexchange.com/a/28853/799
So...
What a random internet stranger thinks you need:
1 VF page. With only 1 constructor, the one that takes StandardSetController.
In the constructor inspect the ssc.getSelected() and query SELECT Id, Name FROM Contact WHERE Id IN :ssc.getSelected() AND Email = null. Save the results of the query into public contactsWithoutEmail {get; private set;}
Do NOT have the action={!send} unless you absolutely need it automated. it should be conscious user's decision to click some final "Do it!" button.
In the send() method query only these SELECT Id, Name FROM Contact WHERE Id IN :ssc.getSelected() AND Email != null and process them.
In visualforce - use <apex:pageBlockTable>, <apex:dataTable> or similar to display contactsWithoutEmail. No need to hand-craft the html.
And I recommend making send a normal apex:commandButton, not action

Writing a Custom Controller extension to get related records and iterate over list/index and use with apex:repeat

I have 3 custom objects with a Master-Detail Relationship and Lookup Relationship.
CustomA__c (related CustomB__c) <-> CustomB__c <-> CustomC_c (related CustomB_cc)
I´ve built a Visualforce page with HTML table to replicate a PDF document and a Custom Controller Extension, so far so good.
But I´m just a beginner with apex coding.
The problem is that I need to replicate the document as it is, when there are no related records for CustomA__c or less then 5, it should still show the full table (the empty rows). Max. rows/related records on the document is 5, no second page needed.
Currently I´m trying to accomplisch that by using apex:variable and apex:repeat as I´ve seen some examples, but perhaps there is also another solution. For the Visualforce page I already wrote the code for the rows with data and another apeax:repeat for the empty rows.
But I´m really strugling with the controller, i know i need to iterate over the list, the code that i already wrote is also put together out of examples as i just don´t understand it yet good enough.
Any help would be appreciated! Thanks, Josip
public with sharing class CustomAController {
public CustomA__c customa{get; set;}
public CustomA__c ca{get; set;}
public CustomAController (ApexPages.StandardController controller) {
ca = (CustomA__c )controller.getRecord();
customa= [SELECT Id, Name FROM CustomA__c WHERE Id = :ApexPages.currentPage().getParameters().get('Id')];
}
public List<CustomB__c > getrelatedCustomB() {
List <CustomB__c > cbList = New List<CustomB__c >(5);
for(CustomA__c acc:[SELECT Id, Name, (SELECT Id, Name, ... , CustomCfield__r.Name FROM CustomBs__r ORDER BY Name LIMIT 5) FROM CustomA__c WHERE Id = :customa.Id]){
for(CustomB__c cb:acc.CustomBs__r)
cbList.add(cb);
}
return cbList;
}
}
You can dramatically simplify your code by writing a direct query on the child object instead of a parent-child SOQL query.
public List<CustomB__c > getrelatedCustomB() {
return [SELECT Id, Name, ... , CustomCfield__r.Name
FROM CustomB__c
WHERE CustomA__c = :customA.Id
ORDER BY Name
LIMIT 5];
}
There's no need to iterate in Apex here.

Salesforce Apex - Populating an object from SOQL query

I have a simple SOQL query that returns information relating to a Contact and CampaignMember. I'm attempting to populate a custom object with the results of the SOQL query. However I get the following error when loading the Visualforce page:
Invalid field campaign.name for CampaignMember
List campaignMembers = [select campaign.name, contact.id,contact.firstname, contact.lastname, status, campaignId from CampaignMember where contactId = '003U000000U0eNq' and campaignId in :campaigns];
for (Integer i = 0; i < campaignMembers.size(); i++) {
results.add(new CampaignMemberResult(
(String)campaignMembers[i].get('CampaignId'),
(String)campaignMembers[i].get('campaign.name'),
true
));
}
I've ran the SOQL query seperately in the Developer Console and it queries successfully. Why can I not pull in the campaign.name from the SOQL query within the for loop?
The error you see is caused by the fact you should write it as campaignMembers[i].Campaign.Name. Or if you insist on the getter syntax, campaignMembers[i].getSobject('Campaign').get('Name').
Any special reason you need the wrapper object (or whatever CampaignMemberResult is)?
I have strange feeling you're writing too much code to achieve something simple ;) The syntax with campaignMembers[i].Campaign.Name will also mean you don't have to use casts to String.
Plus - if you need to know "in which campaigns does this Contact occur" you have 2 ways:
flat
select contact.id,contact.firstname, contact.lastname,
campaignid, campaign.name,
status
from CampaignMember
where contactId = '003U000000U0eNq'
subquery
From contact you go down to the related list of campaignmembers, then up to campaigns to get their names
SELECT Id, FirstName, LastName,
(SELECT CampaignId, Campaign.Name FROM CampaignMembers)
FROM Contact WHERE Id = '003U000000U0eNq'
Example how to use "flat" result straight in visualforce (without CampaignMemberResult):
Apex:
public List<CampaignMember> flatMembers {get;set;} // insert dick joke here
flatMembers = [select contact.id,contact.firstname, contact.lastname,
campaignid, campaign.name,
status
from CampaignMember
where contactId = '003U000000U0eNq'];
VF:
<apex:pageBlockTable value="{!flatMembers}" var="cm">
<apex:column value="{!cm.Contact.LastName}" />
<apex:column value="{!cm.Status}" />
<apex:column value="{!cm.Campaign.Name}" />
EDIT
My end goal is a Visualforce page to be displayed on the contact
record showing a list of all campaigns with a checkbox alongside each
indicating if the contact is a member or not.
You do realize it can quickly grow into a pretty long table? Maybe some filter on campaigns (if you feel like reading about sth advanced - check the documentation for "StandardSetController"). Also I'm pretty sure there are some ways to add Contacts/Leads to Campaigns from Campaign reports - maybe something out of the box would save your time and be more maintainable...
But code solution would be pretty straightforward, start with a helper wrapper class:
public class CampaignWrapper{
public Boolean selected {get;set;}
public Campaign c {get; private set;}
public CampaignWrapper(Campaign c){
this.c = c;
selected = !c.CampaignMembers.isEmpty();
}
}
Then a query and build the list of wrappers:
List<CampaignWrapper> wrappers = new List<CampaignWrapper>();
for(Campaign c : [SELECT Id, Name, (SELECT Id FROM CampaignMember WHERE ContactId = '...')
FROM Campaign
LIMIT 1000]){
wrappers.add(new CampaignMember(c));
}
You should be all set ;) If it's just for displaying - you might not even need the wrapper class (some tricks in visualforce expressions maybe or use Map<Campaign, Boolean> even...
1000 records is the limit of collections passed to Visualforce (10K if your page will be readonly). Past that - pagination, most likely with use with abovementioned StandardSetController.

getting Value of a field by its Name in apex salesforce

in my visualforce page i have some campaign object first user select an object then there is a multi picklist. in this picklist there is Label for all the fields user selects some fields then i have to show the value of these fields in the selected campaign object
for showing multiple picklist my apex function is
public List<SelectOption> getOptionalFields(){
Map <String, Schema.SObjectField> fieldMap= Campaign.sObjectType.getDescribe().fields.getMap();
List<SelectOption> fieldsName =new List<SelectOption>();
for(Schema.SObjectField sfield : fieldMap.Values())
{
schema.describefieldresult dfield = sfield.getDescribe();
fieldsName.add(new SelectOption(dfield.getName(),dfield.getLabel()));
}
but i have no idea how to show value for the the field
for exmple i have object instance like
Campaign c;
now i have to get value of any field whose Name is in string form.how to get corresponding value for that field.one solution is just write like
say
String fieldName;
and use multiple if
if(fieldName=='Name')
c.Name=
if(fieldName=='Id')
c.Id=
is there any other convenient method??please explain!!
You need to read about "dynamic apex". Every "concrete" sObject (like Account, Contact, custom objects) can be cast down to generic sObject (or you can use the methods directly).
Object o = c.get(fieldName);
String returnValue = String.valueOf(o);
There are some useful examples on dynamic get and set methods on Salesforce-dedicated site: https://salesforce.stackexchange.com/questions/8325/retrieving-value-using-dynamic-soql https://salesforce.stackexchange.com/questions/4193/update-a-records-using-generic-fields (second question is a bit more advanced)
You'll still need to somehow decide when to return it as String, when as number, when as date... Just experiment with it and either do some simple mapping or use describe methods to learn the actual field type...

What is the SOQL to get all Public Calendars, in a Salesforce instance?

Does anyone know how to perform a query to get all public calendars? You can see the list by going to Setup ... Customize ... Activities .. Public Calendars and Resources
What are these calendar objects?
My goal is to find a way to show these calendars in a VisualForce page to make it easier for users to find them.
If you run a .getSobjectType() on the ID it comes up as a calendar object. When you try and query that object it says it's not available. It looks like the custom setting is the only route for now.
As near as I can tell, Salesforce hasn't directly exposed the Public Calendar object for customers to query directly.
Public Calendars seem to fall into the 023 namespace, which is a standard object, but I can't find any object in the Schema that have that namespace, which leads me to believe that SFDC has hidden them from us.
If you want to show the list in Visualforce, you could use a workaround using the PageReference GetContent() method on the Calendar page and then fetch the details from the html.
Note that this won't work in APEX triggers..
Public Class CalendarResource{
public Id crId {get;set;}
public String label {get;set;}
public String type {get;set;}
}
Pagereference r = new PageReference('/_ui/common/data/LookupResultsFrame?lkfm=swt&lknm=cal&lktp=023&cltp=resource&lksrch=#');
String html = r.getContent().toString();
List<CalendarResource> cals = new List<CalendarResource>();
Matcher m = Pattern.compile('lookupPick\\(\'swt\',\'cal_lkid\',\'cal\',\'\',\'(.*?)\',\'(.*?)\',\'\',\'\'\\)">(.*?)</a></TH><td class=" dataCell ">(.*?)<\\/td><\\/tr>').matcher(html);
//While there are labels
while (m.find()) {
//system.debug(m.group(3));
//system.debug(m.group(4));
CalendarResource cr = new CalendarResource();
cr.crId = m.group(1);
cr.label = m.group(2);
cr.type = m.group(4);
cals.add(cr);
}
for(CalendarResource cr : cals){
system.debug(cr.crId+'__'+cr.label+'___'+cr.type);
}
You can do this in the current API version by: "SELECT Id,Name FROM Calendar where Type='Resource'

Resources