I have an Object, lets say 'Resources'
Each object have type, lets say 'Contractors'
Each 'Contractor' may have sub-types A, B, C, D
I have visualforce page setup that outputs all 'Contractors' as a table, but I also want to have Sub-types dropdown with A, B, C, D values with option to filter Contractors (Lets say, I select 'A', page will be refreshed, and all contractors with sub-type A appear).
Type and Sub-type are related list (Type is controlling field for sub-type)
I would really appreciate for your help.
Thank you.
I had sort of the same problem and this is how I developed it.
your Visual force page:
<apex:outputPanel id="PanelId">
<apex:selectList size="1" id="firstList" value="{!firstListVauleId}">
<apex:actionSupport event="onchange" action="{!UpdateSelectedFirstItem}" reRender="PanelId"/>
<apex:selectOptions value="{!FirstListOptions}" />
</apex:selectList>
<apex:selectList size="1" id="secondList" value="{!secondValueId}">
<apex:selectOptions value="{!SecondListOptions}" />
</apex:selectList>
</apex:outputPanel>
your apex class:
public String firstListVauleId {get;set;}
public String secondListVauleId {get;set;}
public List<SelectOption> getfirstListOptions()
{
List<SelectOption> options = new List<SelectOption>();
// add items add needed. you can make database queries.
return options;
}
public List<SelectOption> getsecondListOptions()
{
List<SelectOption> options = new List<SelectOption>();
// add options based on the first list selection. you can make database queries.
return options;
}
public void UpdateSelectedFirstItem()
{
// do your stuff if you need to do anything upon changing the first dropdown selected item.
}
Related
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
*New to SF development *
I'm working toward this end goal; Create a custom button on the Opportunity. When that button is pushed, a VisualForce page will display records from 2 custom objects that have a relationship to that Opportunity(ID). Both custom objects relate to the Opportunity via a custom lookup field.
As a rookie, I'm not sure if I'm starting in the right spot. Here is how I'm trying to in my head. The code below is for items #1 & #2 below.
Create a class methods that query the separate data. Each method would be a separate query/list
Include coding to pull in a variable of the current Opportunity ID
Create VisualForce page that displays queried data
Create button that triggers the APEX Code
public with sharing class TestDisplayQueryList{
public Opportunity currRec {get; set;}
public static List<Opportunity> oppRecords {get; set;}
public static List<Billing__c> billRecords {get; set;}
public static List<Service__c> servRecords {get; set;}
public TestDisplayQueryList(){
currRec = [SELECT ID FROM Opportunity WHERE :ApexPages.currentPage().getParameters().get('id')];
oppRecords = [SELECT Name, StageName ID FROM Opportunity WHERE ID= :currRec];
billRecords = [SELECT Name, Invoice ID FROM Billing WHERE Opportunity_Name_c= :currRec];
servRecords = [SELECT Name, Department ID FROM Service WHERE Opportunity_Name_c= :currRec];
}
}
3.) there are a bunch of ways to do this, The simplest is just a pageblock table
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_quick_start_iteration_components.htm
put your value as your list from your controller, you will need a seperate pageblock table for each list.
4.)
Create a custom button or link, you can do this using salesforce custom button, Just make it a url and pass it the ?id at the end of the url. This will automatically cause the code to run because the code can be ran upon page initialization. you will place this button on the opportunity page.
If you want to show the infromation in a popup window( which will be look and act better for the system) you can also do a custom button, just do a javascript button. there are a ton of tutorials online for making a button for a popup window in javascript. the javascript can extend to the controller and pass the opportunity id as well.
If you get stuck, please let me know and best of luck!
To be honest you could do this much easier than you think.
VisualForce has an abundance of standard components that can be used for tasks like this.
Below is an example VisualForce page for you:
<apex:page standardController="Opportunity" extensions="OpportunityExt">
<!-- Either include all related lists by setting the relatedList attribute to true -->
<apex:detail subject="{!opportunity.Id}" relatedList="false"/>
<!-- Or by Including the related lists seperately -->
<apex:relatedList list="OpportunityLineItems" />
<apex:relatedList list="OpportunityCompetitors" />
<!-- To use a button to display a panel, create the panel to reRender after our button action is complete -->
<apex:outputPanel id="thePanel">
<!-- Then create the buttons -->
<apex:commandButton action="{!showThePanel}" value="Show Panel" reRender="thePanel" rendered="{!NOT(showPanel)}"/>
<apex:commandButton action="{!hideThePanel}" value="Hide Panel" reRender="thePanel" rendered="{!showPanel}"/>
<!-- And inside that panel create a block that will only render when the flag is set -->
<!-- Note the use of outputPanel and outputText differently -->
<!-- OutputText leaves no container behind, outputPanel does so we need it for the "identifying panel" -->
<apex:outputText rendered="{!showPanel}">
<!-- You can then include the related lists you wanted -->
<apex:relatedList list="OpenActivities" />
</apex:outputText>
</apex:ouputPanel>
</apex:page>
And this would be the extension for that page:
public with sharing class OpportunityExt {
private Opportunity theOpportunity;
public Boolean showPanel {get; private set;}
public OpportunityExt(ApexPages.StandardController controller) {
// Get the Opportunity from the standard controller
theOpportunity = (Opportunity) controller.getRecord();
// By default don't display the panel - or do, it's your task
showPanel = false;
}
public void showThePanel() {
showPanel = true;
}
public void hideThePanel() {
showPanel = false;
}
}
For your reference here are the documentation links:
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_page.htm
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_detail.htm
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_relatedList.htm
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_commandButton.htm
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_outputPanel.htm
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_outputText.htm
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_controller_extension.htm
I have two custom objects, X and Y.
The object Y is related to X by lookup YretatedX__c.
I am trying to show all Y related to X y standart page of X whith a visualforce.
Visualforce:
<apex:page standardController="X__c" extensions="related_list">
<apex:detail relatedList="true">
<apex:relatedList list="Y__c" subject="{!AllRelated}"/>
</apex:detail>
</apex:page>
Apex Class:
public class related_list {
private X__c x;
private Id idX;
public List<Y__c> AllRelated = new Y__c[]{};
public related_list(ApexPages.StandardController controller) {
this.x=(X__c)controller.getRecord();
idX = this.x.Id;
}
public List<Y__c> getAllRelated() {
AllRelated = [SELECT id FROM Y__c WHERE YretatedX__c =: this.idX];
return AllRelated;
}
}
In X page, the visualforce only shows:
Invalid parameter value "[a120E0000001234567, a120E0000007654321]" for parameter "id"
This Ids are valid for Y objects retated to this X object
I tried a lot, but I can find a solution.
I think you're not understanding the attributes of the apex:relatedList component in Visualforce.
Refer to this:
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_relatedList.htm
Note that you don't actually need to query for the records to display them with the component.
All you need is this:
<apex:relatedList list="Contacts"/>
You need to specify the Relationship Name for the list attribute
You don't need to specify the subject (the subject is the record who is the Parent of the list you are trying to show) as this would automatically be populated by the Standard Controller
Hope that helps.
I found a solution using <apex:pageBlockTable instead of <apex:relatedList
<apex:page standardController="X__c" extensions="related_list">
<apex:pageblock id="CustomList" title="Y" >
<apex:pageBlockTable value="{!AllRelated}" var="y" rendered="true">
<apex:column value="{!y.id}"/>
</apex:pageBlockTable>
</apex:pageblock>
</apex:page>
I am an amateur developer looking for a unique solution that Google doesn't have an answer to.
I need to create a time-table for a class. There are 6 hours with 6 teachers assigned to each subject. For the subject that I select, the respective teachers should be shown in the corresponding list.
Refer the VF code below:
<b><i>{!$ObjectType.Class__c.fields.Firts_Hour_Subject__c.label}</i></b>
<apex:selectList size="1" multiselect="false" value="{!selectedSubject}">
<apex:selectOptions value="{!Subject}"/>
<apex:actionSupport event="onchange" reRender="render1"/>
</apex:selectList>
<b><i>{!$ObjectType.Class__c.fields.First_Hour_Teacher__c.label}</i></b>
<apex:selectList size="1" multiselect="false" id="render1">
<apex:selectOptions value="{!RelatedTeacher}"/>
</apex:selectList>
This repeats for a total of 6 times. I want to not create and pass 6 values, instead I want to use a single variable/array to pass the values to apex.
This is the apex code:
public class listReturn {
public String SelectedSubject {get;set;}
//Other code.....
//This is the method that returns the list of teachers based on subjects.
public List<SelectOption> getRelatedTeacher(){
List<SelectOption> RelatedTeacher=new List<SelectOption>();
List<Teacher__c> teach = new List<Teacher__c>();
teach = [select Teacher__c.Name from Teacher__c where Teacher__c.Subject_del__r.Name = :SelectedSubject];
RelatedTeacher.add(new SelectOption('--SELECT TEACHER--','--SELECT TEACHER--'));
for(Teacher__c e:teach){
RelatedTeacher.add(new SelectOption(e.Name,e.Name));
}
return RelatedTeacher;
}
}
(Edit) here I want to achieve something similar to dependent lookup field that is available in customization..now with that in mind I'm trying to pass the value from the subject selectlist to {!selectedSubject} in apex..the problem I'm facing is that my final output only takes value of last selectlist and returns the teacher list for all of the other selectlists..I want to use the same {!selectedsubject} var and control the teacher list based on the input from the other subject selectlists.
Thanks in advance!
You can use <apex:repeat> and drive it by a list of hours.
I have a list of Assets
Name: column 2: etc
A1 C1 b1
A2 c2 b2
When I click on A1, I call action="{! assetClicked}" within to do some logic, but I cannot redirect it to another Visual Force Page
If I use I can link to another VF page, but cannot do action="{! assetClicked}"
Is there a way to combine them together or some other way around?
Page Code:
<apex:form >
<apex:commandLink action="{! assetClicked}" value="{!wn.name}" id="theCommandLink">
<apex:param value="{!wn.name}" name="id" assignTo="{!selectedAsset}" ></apex:param>
<apex:outputLink value="/{!wn.id}" id="eventlink">{!wn.name}</apex:outputLink>
</apex:commandLink>
</apex:form>
You would need to use the PageReference class.
Here's a modified example from the documentation:
// selected asset property
public string selectedAsset {get;set;}
public PageReference assetClicked()
{
// Your code here
PageReference redirect = new PageReference('/apex/PageName');
// pass the selected asset ID to the new page
redirect.getParameters().put('id',selectedAsset);
redirect.setRedirect(true);
return redirect;
}
Alternatively, you could use Page.PageName; instead of new PageReference('/apex/PageName'); as described here.
You didn't indicate how to retrieve the parameter in the desintation Visualforce page controller. I found this in a different forum:
// Assuming the parameter is 'id' after redirecting to page2 you can retrieve the paramter thus
public customcontrollerpage2() {
String ID = ApexPages.currentPage().getParameters().get('id');
}
In button method add something like this at the end of the method:
PageReference pr = new PageReference('/apex/YOUR_PAGE_NAME');
return pr;