It is very handy to disable buttons after they have been pressed. This lets the user know that the button was in fact pressed, and it prevents the button’s action from being executed multiple times. The Visulforce component apex:actionStatus gives us an easy way to accomplish this. Here are some things to take note of in the example.
The command button must have a rerender parameter
Command buttons must be in an apex:outputPanel, so both buttons appear on the page when each apex:facet is active.
The action status will only disable one set of buttons for a apex:pageBlock at a time. If ‘both’ is specified for the button location, only the clicked set of buttons on top or bottom will be disabled while processing. I usually select only one location to prevent additional button clicks.
Add the immediate=”true” attribute to the Cancel. This bypasses Visualforce validation that would normally fire on the form.
ExamplePage.page
ExamplePageController.cls
public with sharing class ExamplePageController {
public ExamplePageController() {
// do constructor logic
}
public PageReference DoSave() {
// do save logic
return null;
}
public PageReference DoCancel() {
// do cancel logic
return null;
}
}
Eclipse doesn’t currently offer an option to beautify Apex code. Sorry about the trick title. However, I will describe techniques that will help you clean up your code’s indentation. Neither way is perfect, but they have helped me make my code more readable. In the meantime, vote up this idea for the enhancement.
Method 1: Developer Console
This technique uses the Developer Console to indent the source code. Then we refresh the code in Eclipse.
In the Developer Console
Open the class
Select all or just a section of code to indent
Press Shift + Tab
Save
In Eclipse
Right-click the class name
Select ‘Force.com’ -> ‘Refresh from Server’
Method 2: NotePad++ with the TextFX plugin
If you use Windows and don’t have NotePad++, download it now. It is an incredibly helpful free text utility. The plugin called TextFX has a feature to reindent code. The menu for TextFX plugin appears after it is installed. The plugin feature is intended for C++, but it also works well for APEX. I think this does a better job than the Developer Console.
Copy your code from Eclipse
Paste it into a Notepad++ window
Select ‘TextFX’ -> ‘TextFX Edit’ -> ‘Reindent C++ code’
Copy the indented code
Paste it back into Eclipse
The function will indent with tabs by default. It can be changed to use spaces by selecting ‘Settings’ -> ‘Preferences…’ -> ‘Tab Settings’.
Bonus: Indent Visualforce
This can be done in the Eclipse Force.com IDE. However, be careful because it will sometimes remove an end bracket when it is in a style attribute. For example: <div style=”width: {!MyWidth}”> will end up like <div style=”width: {!MyWidth”>
Select the section of Visualforce code that you want to indent
Press Ctrl + Shift + F
Eclipse editor preferences control the number of spaces that Visualforce is indented. To change the spacing, select ‘Window’ -> ‘Preferences’. Expand ‘Web’ -> ‘HTML Files’ -> ‘Editor’.
Below is a component that will allow you to search and select Users. It was created to mimic the experience of selecting multiple users in the Task creation window. However, it would be easy to change the reference from the User object to almost any other object.
An initial list of selected users can be assigned by passing an Id list in the component attribute aInitialRightList. The list referenced in the aCurrentRightList attribute will be updated anytime entries in the right multiselect picklist change. The aWidth attribute accepts px or %, and it sets the width of the entire component.
public with sharing class UserMultiSelectComponentController {
public static final String USERTYPE_STD = 'Standard';
public list InitialRightList {get;set;}
public list CurrentRightList {get;set;}
public String SearchText {get;set;}
public list LeftSelectedList {get;set;}
public list RightSelectedList {get;set;}
map LeftOptionMap = new map();
map RightOptionMap = new map();
/****
* Controller - instantiate lists
****/
public UserMultiSelectComponentController() {
LeftSelectedList = new list();
RightSelectedList = new list();
}
/****
* ClickRight - Right pointing arrow was clicked. Move selected options to the right box.
****/
public PageReference ClickRight(){
RightSelectedList.clear();
for(String s : LeftSelectedList){
if (LeftOptionMap.containsKey(s)) {
RightOptionMap.put(s, LeftOptionMap.get(s));
}
LeftOptionMap.remove(s);
}
return null;
}
/****
* ClickLeft - Left pointing arrow was clicked. Move selected options to the left box.
****/
public PageReference ClickLeft(){
LeftSelectedList.clear();
for(String s : RightSelectedList){
if (RightOptionMap.containsKey(s)) {
LeftOptionMap.put(s, RightOptionMap.get(s));
}
RightOptionMap.remove(s);
}
return null;
}
/****
* getLeftOptionList - return SelectOptions for the left/unselected box
****/
public list getLeftOptionList(){
list TempOptionList = new list();
list TempValueList;
TempValueList = LeftOptionMap.values();
TempValueList.sort(); // sort by name
for (User u : TempValueList) {
TempOptionList.add(new SelectOption(u.Id, u.Name));
}
return TempOptionList;
}
/****
* getRightOptionList - return SelectOptions for the right/selected box
****/
public list getRightOptionList(){
list TempOptionList = new list();
list TempValueList;
list UserList;
//clear is used instead of new list, so the list maintains the pointer to the ExamplePageController list
CurrentRightList.clear();
// load initially selected records into the right box
if (InitialRightList != null && InitialRightList.size() > 0) {
UserList = [Select Name, Id, IsActive, UserType From User where IsActive=true and UserType = :USERTYPE_STD and Id IN :InitialRightList limit 500];
for (User u : UserList) {
RightOptionMap.put(u.Id, u);
}
InitialRightList.clear();
}
TempValueList = RightOptionMap.values();
TempValueList.sort(); // sort by name
for (User u : TempValueList) {
TempOptionList.add(new SelectOption(u.Id, U.Name));
CurrentRightList.add(u.Id);
}
return TempOptionList;
}
/****
* Find - Search for user records by name, and add them to the left box
****/
public PageReference Find(){
String TempSearchText;
list UserList;
TempSearchText = '%' + SearchText + '%';
UserList = [Select Name, Id, IsActive, UserType From User where IsActive=true and UserType = :USERTYPE_STD and Name like :TempSearchText limit 500];
LeftOptionMap.clear();
for (User u : UserList) {
if (!RightOptionMap.containsKey(u.Id)) {
LeftOptionMap.put(u.Id, u);
}
}
return null;
}
}
ExamplePage.page
ExamplePageController.cls
public with sharing class ExamplePageController {
public list InitialList {get;set;}
public list CurrentList {get;set;}
public ExamplePageController() {
InitialList = new list();
InitialList.add(UserInfo.getUserId());
CurrentList = new list();
}
}
UserMultiSelectComponentControllerTest.cls
@isTest
private class TestUserMultiSelectComponentController {
static testMethod void TestUserMultiSelect() {
list TempOptionList;
list UserList;
UserMultiSelectComponentController UMSCcontroller = new UserMultiSelectComponentController();
// set initial user
UserList = [Select Name, Id, IsActive, UserType From User where IsActive=true and UserType = :UserMultiSelectComponentController.USERTYPE_STD limit 1];
system.Test.startTest();
// instantiate lists that would be passed in
UMSCcontroller.InitialRightList = new list();
UMSCcontroller.CurrentRightList = new list();
// initial list item should show in right list, left should be empty
UMSCcontroller.InitialRightList.add(UserList[0].Id);
TempOptionList = UMSCcontroller.getLeftOptionList();
system.assertEquals(0, TempOptionList.size());
TempOptionList = UMSCcontroller.getRightOptionList();
system.assertEquals(UserList[0].Id, TempOptionList[0].getValue()); // returned option list
system.assertEquals(UserList[0].Id, UMSCcontroller.CurrentRightList[0]); // current right list
// run find method, this will add entries to the left LeftOptionMap that get put into a list in getLeftOptionList
UMSCcontroller.SearchText = ''; // so search text is not null
UMSCcontroller.Find(); // assumes there are 2 or more standard users
TempOptionList = UMSCcontroller.getLeftOptionList();
system.assertNotEquals(0, TempOptionList.size()); //not 0
// Select entry to move to right box
UMSCcontroller.LeftSelectedList.add(TempOptionList[0].getValue());
UMSCcontroller.ClickRight();
TempOptionList = UMSCcontroller.getRightOptionList(); // update CurrentRightList with 2 selected ids
system.assertEquals(2, UMSCcontroller.CurrentRightList.size());
// Select entry to move to left box
UMSCcontroller.RightSelectedList.add(UserList[0].Id);
UMSCcontroller.ClickLeft();
TempOptionList = UMSCcontroller.getRightOptionList(); // update CurrentRightList with 1 selected ids
system.assertEquals(1, UMSCcontroller.CurrentRightList.size());
system.assertEquals(TempOptionList[0].getValue(), UMSCcontroller.CurrentRightList[0]);
system.Test.stopTest();
}
}
Retrieve field data for a record using the Standard Controller object in a Controller Extension class
public with sharing class MyController {.
Account MyAccount;
Id MyId;
public MyController(ApexPages.StandardController controller) {
list MyFieldList;
// get the record
// passing a list of field names to the standard controller will cause
// the standard controller to retrieve the field data of the record
MyFieldList = new list{'Id', 'Name', 'BillingCity', 'BillingState', 'MyCustomField__c'};
controller.addFields(MyFieldList);
MyAccount= (Account)controller.getRecord();
// another way to get more fields. use the addFields method
// by default only fields referenced in the VisualForce page are retrieved.
controller.addFields(new list{'ShippingCity', 'ShippingState'});
// get the record id
// this is the record id of the query string in the URL
MyId = controller.getId()
}
}