function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Paul AllsoppPaul Allsopp 

New Developer: Button Object Instantiation

Problem: I want to create a row of, say 20, buttons dynamically using an Apex class.

How do I create a commandButton instance in a class and assign it the required properties?
Something along the lines of:
CommandButton cb = new CommandButton();
cb.value = "My button";
cb.action = "{!my_action}";
As I said in the title, I am a complete novice in VF/Apex, but a seasoned developer in other languages.

Any help is greatly appreciated.
Paul
 
Best Answer chosen by Paul Allsopp
Paul AllsoppPaul Allsopp
In case this helps anyone else, I changed the component markup to
<apex:outputPanel layout="block">
	<apex:dynamicComponent componentValue="{!apex_button_panel}" id="search_letters" />
</apex:outputPanel>
and the component code to
public class BrowseBy {

	public Component.Apex.OutputPanel generateButtons() {
		Component.Apex.OutputPanel panel = new Component.Apex.OutputPanel();
		panel.id = 'search_by_letter_panel';
		for (integer i = 65; i < 91; i ++) {
			String letter = i.format();
			Component.Apex.CommandButton cb = new Component.Apex.CommandButton();
			cb.value = EncodingUtil.urlDecode(letter, 'UTF-8');
			panel.childComponents.add(cb);
		}
		
		return panel;
	}
}
then in my controller
public transient Component.Apex.OutputPanel apex_button_panel {get; set;}

It seems obvious now...I was trying to serialize a list because I didn't want to iterate it, but in hindsight I shouldn't have even been using a list.

Loving Apex and VF...this is my first play with it
 

All Answers

Paul AllsoppPaul Allsopp
OK, after some more digging I found I could instantiate a command button by calling Component.Apex.CommandButton, which prompted me to create this class method:
public class BrowseBy {

	public List<Component.Apex.CommandButton> generateButtons() {
		List<Component.Apex.CommandButton> object_apex;
		for (integer i = 65; i < 91; i ++) {
			String letter = i.format();
			Component.Apex.CommandButton cb = new Component.Apex.CommandButton();
			cb.value = EncodingUtil.urlDecode(letter, 'UTF-8');
			object_apex.add(cb);
		}
		
		return object_apex;
	}
}
...the problem is, I now get a System.NullPointerException: Attempt to de-reference a null object error located at Class.BrowseBy.generateButtons: line 9, column 1
 
Paul AllsoppPaul Allsopp
Haha! This is like a journey of discovery...I forgot to instantiate my list object above.
List<Component.Apex.CommandButton> object_apex;
should have been
List<Component.Apex.CommandButton> object_apex = new List<Component.Apex.CommandButton>();

However, I do get a new error:
System.SerializationException: Not Serializable: com/salesforce/api/fast/List$$lcom/salesforce/api/VisualForceComponent/Component/apex/commandbutton$$r
Paul AllsoppPaul Allsopp
I suspect this is caused by my trying to output the buttons as if they were a value, but not sure how to output them.
My compnent markup is thus
<apex:component controller="Company">
	<script>
		j$(document).ready(function() {});
	</script>
	<apex:outputPanel >
		{!apex_buttons}
	</apex:outputPanel>
</apex:component>


I'm guessing my reference to {!apex_buttons} cannot be like this
Paul AllsoppPaul Allsopp
In case this helps anyone else, I changed the component markup to
<apex:outputPanel layout="block">
	<apex:dynamicComponent componentValue="{!apex_button_panel}" id="search_letters" />
</apex:outputPanel>
and the component code to
public class BrowseBy {

	public Component.Apex.OutputPanel generateButtons() {
		Component.Apex.OutputPanel panel = new Component.Apex.OutputPanel();
		panel.id = 'search_by_letter_panel';
		for (integer i = 65; i < 91; i ++) {
			String letter = i.format();
			Component.Apex.CommandButton cb = new Component.Apex.CommandButton();
			cb.value = EncodingUtil.urlDecode(letter, 'UTF-8');
			panel.childComponents.add(cb);
		}
		
		return panel;
	}
}
then in my controller
public transient Component.Apex.OutputPanel apex_button_panel {get; set;}

It seems obvious now...I was trying to serialize a list because I didn't want to iterate it, but in hindsight I shouldn't have even been using a list.

Loving Apex and VF...this is my first play with it
 
This was selected as the best answer