+ Start a Discussion
NMackeyNMackey 

Visualforce page that displays multiple sobjects

I'm developing an application that contains multiple custom objects whose records function as more or less static data that is looked up in another custom object by the user.

 

I'm talking accounts, currencies etc except there are around 10 custom objects in all.

 

I want to have a single page that lets me select the custom object type from a drop down and display something similar to the default controller's list view.

 

So far, I've just been showing and hiding blocks of html to achieve this result but it's not really an ideal way of doing this in terms of code reuse. Is there any more generic way I can display info about multiple custom objects on a single page?

Best Answer chosen by Admin (Salesforce Developers) 
MikeGinouMikeGinou

To maximize code re-use, you'll need to create some generic wrapper classes. Probably something representing a rows and cells at a minimum. Possibly columns, too.

 

Then you write the page and components so that they use the rows and cells to perform all the layout. Therefore the rows and cells need to contain sufficient information (size, alignment, etc) to help you do that. Intelligent defaults will go a long way here.

 

Finally you need to write some adapter pieces that will take the actual data out of SOQL queries and generate your new custom rows and cells.

 

If you need to add new SObjects later, you'll only need to add a new adapter and you should be able to re-use the page and components just fine.

All Answers

Jeremy.NottinghJeremy.Nottingh

Well, let's see. Can you use the same column names for each object? You could set up a class in your custom controller with standardized attributes equivalent to fields on the objects you want to display. 

 

If they need different columns and everything, I think using 10 outputpanels with rendered= attributes to hide the unused ones is probably your best bet.

 

Jeremy

 

 

MikeGinouMikeGinou

To maximize code re-use, you'll need to create some generic wrapper classes. Probably something representing a rows and cells at a minimum. Possibly columns, too.

 

Then you write the page and components so that they use the rows and cells to perform all the layout. Therefore the rows and cells need to contain sufficient information (size, alignment, etc) to help you do that. Intelligent defaults will go a long way here.

 

Finally you need to write some adapter pieces that will take the actual data out of SOQL queries and generate your new custom rows and cells.

 

If you need to add new SObjects later, you'll only need to add a new adapter and you should be able to re-use the page and components just fine.

This was selected as the best answer
NMackeyNMackey

Thanks Mike and Jeremy,

 

I have started writing a simple wrapper class around multiple sObjects as suggested by Jeremy since initially, I need only display edit/view command links and the record's name in a grid but I Mike's suggestion appeals to me.

 

I'll have to go and look at how to implement more generic wrapper classes and visualforce components before I can attempt that though.

NMackeyNMackey

I'm having a bit of a problem getting this implemented. I'm using an attribute to set the data I'm trying to render in my custom component, but when I specify an inner class as the data type, I get an error telling me:


Save error: Apex class 'datagridcontroller.datagrid' does not exist.

 

The documentation on the type attribute of <apex:attribute> says:

 

The Apex data type of the attribute. If using the assignTo attribute to assign the value of this attribute to a controller class variable, the value for type must match the data type of the class variable. Only the following data types are allowed as values for the type attribute: primitives, such as String, Integer, or Boolean; sObjects, such as Account, My_Custom_Object__c, or the generic sObject type; one-dimensional lists specified using array-notation, such as String[], or Contact[]; and custom Apex types (classes).

  

 

The component code:

 

<apex:component controller="DataGridController">
	<apex:attribute name="data" description="dataGrid to display" type="DataGridController.DataGrid" required="true" assignTo="{!Data}" />
	<table id="dataGrid" class="list" border="0" cellSpacing="0"
		cellPadding="0">
		<tbody>
			<tr class="headerRow">
				<apex:repeat value="{!Data.ColumnNames}" var="col">
					<th>{!col}</th>
				</apex:repeat>
			</tr>
			<apex:repeat value="{!Data.Rows}" var="row">
				<tr class="dataRow">
					<apex:repeat value="{!row.Cells}" var="cell">
						<td>{!cell.Name}</td>
					</apex:repeat>
				</tr>
			</apex:repeat>
		</tbody>
	</table>
</apex:component>

 

And the controller code:

 

public with sharing class DataGridController 
{
	public DataGrid Data {get; set;}
	
	public class DataGrid
    {
    	private List<DataRow> rows;
    	private List<String> columnNames; 
    	
    	public DataGrid()
    	{
    		rows = new List<DataRow>();
    		columnNames = new List<String>();
    	}
    	
    	public DataRow[] getRows()
    	{
    		return rows;
    	}
    	
    	public String[] getColumnNames()
    	{
    		return columnNames;
    	}
    }
    
    public class DataRow
    {
    	private List<DataCell> cells;
    	
    	public DataRow()
    	{
    		cells = new List<DataCell>();	
    	}
    	
    	public DataCell[] getCells()
    	{
    		return cells;
    	}
    }
    
    public class DataCell
    {
    	public DataCell(string name)
    	{
    		this.Name = name;
    	}
    	
    	public String Name { get; set; }
    }
}

 

MikeGinouMikeGinou

This is not going to be the most helpful post ever.....

 

Split the inner classes out into full class files of their own. You should be fine at that point.

NMackeyNMackey

Thanks for the reply. I had pretty much resigned myself to that fact while taking a break from coding if I didn't get an answer here!

 

I would be interested to see if this is something I'm doing wrong or a bonafide limitation of <apex:attribute>.

 

 

Kirk F.ax361Kirk F.ax361

Just following up:  was the previous suggestion the resolution to this problem?  If so, would you have working code to post?  I'm also curious about a good example of passing a custom class into a component via Apex:attribute  -- I haven't seen one.