1

My visualforce component has the following attribute:

<apex:attribute type="SObject[][]" name="var" 
    description="Variable to store results in." 
    assignTo="{!searchResults}" required="true"/>

My components controller has the following variable:

public List<List<SObject>> searchResults {get; set;}

My page's controller has the following variable:

public List<List<SObject>> searchResults {get; set;}

My page references my component as such:

<c:EmailRecipientSearch var="{!searchResults}"/>

I am getting the following error when deploying:

force-app\main\default\pages\SendEmailForm.page Wrong type for attribute . Expected SObject[][], found VisualforceArrayList

The question:

How do I pass a List<List<SObject>> to a component via an attribute.

I know I could create a wrapper class and pass that instead but I'd like to avoid that.

The use case:

I need to pass data from my component back to my page. This was something I've done in the past but have forgotten how to make it work. I read through this question. I vaguely remembered being able to make it work without passing the entire controller and I wanted to test if my memory was correct.

I understand I can test this without needing to past a List<List<SObject>> but I do have a few other use cases where I would need to pass a nested list as an attribute so I figured I'd ask if anyone knew.

2 Answers 2

3

Sad to say, the VF Custom Components documentation is explicit

One-dimensional lists, specified using array-notation, such as String[], or Contact[].

You'll need to pass a custom type instead.

0

Visual force is pretty good at auto-casting values to the correct object type. For most usages you can probably just declare the parameter as type Object[]. For your particular example I might use:

<apex:attribute type="Object[]" name="var" 
    description="Variable to store results in." 
    assignTo="{!searchResultsAttr}" required="true"/>

Where you controller instead uses:

public List<Object> searchResultsAttr { get; set;}

public List<List<SObject>> searchResults {
    get { return (List<List<SObject>>)searchResultsAttr; }
    set { searchResultAttr = (List<Object>)value; }
}

Just so my controller will also have easy access to the casted value.

But more often that not, I find my usage doesn't requiring casting inside the controller. For example:

<apex:attribute name="query" description="Query to use" type="String" required="true" assignTo="{!queryString}" />
<apex:attribute name="params" description="An array of parameters to use in the query" type="Object[]" required="false" assignTo="{!queryParams}" />

with:

public String queryString { get; set; }

public List<Object> queryParams { get; set; }

Object getQueryParam(Integer i) {
    Object retval = null;
    if(queryParams != null && queryParams.size() > i) {
        retval = queryParams[i];
    }
    return retval;
}

public ApexPages.StandardSetController getStandardSetController() {
    ApexPages.StandardSetController retval = null;
    if(queryString != null) {
        final Object param0 = getQueryParam(0);
        final Object param1 = getQueryParam(1);
        final Object param2 = getQueryParam(2);
        final Object param3 = getQueryParam(3);
        final Object param4 = getQueryParam(4);
        final Object param5 = getQueryParam(5);
        final Object param6 = getQueryParam(6);
        final Object param7 = getQueryParam(7);
        final Object param8 = getQueryParam(8);
        final Object param9 = getQueryParam(9);
        retval = new ApexPages.StandardSetController(
            Database.getQueryLocator(queryString) );
    }
    return retval;
}

Have fun.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .