3

Working from the fieldsets section of the Visualforce Developer's Guide, I can build a table based on a fieldset for a given sObject type, for example (error handling elided for clarity):

// Controller code
// assume this.fs already set to a valid Schema.FieldSet on My_Object__c
// this.fs must be transient or getter - cannot serialize a Schema.FieldSet
public List<Schema.FieldSetMember> getFields() {
  return this.fs.getFields();
}

public List<My_Object__c> getObjectList() {
  string soql = SchemaUtils.getFieldSetSOQL(this.fs);
  return (list<My_Object__c>)Database.query(soql);
}

The method SchemaUtils.getFieldSetSOQL() is one of my standard util methods and does what it says on the tin. Now in the VF page I can build the table dynamically:

<apex:pageBlockTable value="{!objectList}" var="obj">
  <apex:repeat value="{!fields}" var="fld">
    <apex:column headerValue="{!fld.label}" value="{!obj[fld.fieldPath]}" />
  </apex:repeat>
</apex:pageBlockTable>

That works fine. But is it possible to make getObjectList() generic, returning list<sObject> instead of a list of a concrete sObject type? When I try that, the VF page won't save, although the error message is "null". I'm guessing that the VF engine needs the type info that a concrete sObject would provide, but I'm wondering if there's a workaround. My fallback will be full dynamic apex, but if I can make standard VF tags work I'd prefer to do so and keep the code simpler.

Update: after @sfdcfox commented that generic sObjects work for him, I took another try, and observed weird behavior. If I change the controller to return a generic sObject list, the VF page works fine, with 2 different sObject types. But I can no longer save the VF page. Removing the value="{!obj[fld.fieldPath]}" from the column tag will let me save it, as will changing the controller back to a concrete sObject class. I've tried saving via MavensMate (from Atom) as well as directly in the Developer Console; if obj references a generic sObject, then {!obj[fld.fieldPath} causes it to fail, and the error message is null.

Update 2: See my comment on @sfdcfox's answer; this appears to be a VF bug. @sfdcfox's answer shows a good workaround.

2
  • You're doing something else wrong, unfortunately. I just tested it with SObject[] instead of a concrete list, and it works. You might need to share more code.
    – sfdcfox
    Dec 10, 2016 at 17:38
  • @sfdcfox See my update above. Very odd. Going to try putting your sample code into my org and see if I observe anything different. Dec 10, 2016 at 17:58

1 Answer 1

3

I've created a working demo of this. You need to regenerate your field set or simply store the fields. I've use the regenerative version in this demo. As usual, error checking is not present, as an exercise to the reader.


public class SchemaUtil {
    public static String getFieldSetSOQL(FieldSet source) {
        String[] fields = new String[0];
        for(FieldSetMember field: source.getFields()) {
            fields.add(field.getFieldPath());
        }
        return 'SELECT '+String.join(fields,',')+' FROM '+String.valueOf(source.getSObjectType());
    }
}

public class SchemaUtilDemoCtrl {
    String fsName, fsObject;
    transient FieldSet fs;
    public SchemaUtilDemoCtrl() {
        fsName = ApexPages.currentPage().getParameters().get('fieldSetName');
        fsObject = ApexPages.currentPage().getParameters().get('fieldSetObject');
    }

    public FieldSet getFields() {
        if(fs == null) {
            fs = Schema.getGlobalDescribe().get(fsObject).getDescribe().fieldSets.getMap().get(fsName);
        }
        return fs;
    }

    public SObject[] getRecords() {
        return Database.query(SchemaUtil.getFieldSetSOQL(getFields()));
    }
}

<apex:page controller="SchemaUtilDemoCtrl">
    <apex:form> <!-- form to force view state -->
        <apex:pageBlock>
            <table>
                <tr>
                    <apex:repeat value="{!fields.fields}" var="f">
                        <td>{!f.label}</td>
                    </apex:repeat>
                </tr>
                <apex:repeat value="{!records}" var="record">
                    <tr>
                        <apex:repeat value="{!fields.fields}" var="f">
                            <td>
                                {!record[f.fieldPath]}
                            </td>
                        </apex:repeat>
                    </tr>
                </apex:repeat>
            </table>
        </apex:pageBlock>
    </apex:form>
</apex:page>
2
  • I pasted your controller and class into my org, and they compiled just fine. Then I replaced your HTML table with an apex:pageBlockTable using the same apex:repeat/apex:column construction I used in my original question, and I get the same error. So it appears to be a bug in apex:pageBlockTable and/or apex:column. Thanks for the working demo, would not have tracked this down nearly so quickly without it. @sfdcfox Dec 10, 2016 at 18:11
  • @JasonClark probably the column, I'd imagine. I don't know of a working example that uses pageBlockTable, so you might just be right.
    – sfdcfox
    Dec 10, 2016 at 18:24

You must log in to answer this question.

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