5

Fieldsets can reference fields in related objects, something like Opportunity.Account.Name.

If you iterate over such FieldSetMembers on a Visualforce page and try to render a fields inline help text it will fail on such related fields. Probably as a field of that Name cannot be found in the Schema of the root object.

I thought of building such a Map<FieldSetMember.Fieldpath, HelpText> myself but struggled getting the DescribeFieldResult of a FieldSetMember.

2
  • Curious on the unaccept. Did you find something better? – Adrian Larson Jan 23 '19 at 14:06
  • Thanks for pointing me there. Was by accident. I was browsing though questions related to a current problem and must have clicked at the wrong spot. Still best solution so far. – Robert Sösemann Jan 23 '19 at 15:06
5
+50

If you want a tool that can understand cross object relationships, you are going to need a sophisticated approach indeed. It may be worth separating into the following tasks:

  1. Get the referenceTo results for each field. Depending on how many times you are reusing this functionality in one context, it may be worth caching.
  2. Differentiate if you are at a root field or if you need traverse deeper into the map.
  3. Differentiate between standard and custom lookups and be able to convert the cross-object reference into the name of the field (e.g. Account.Name => AccountId).

If I had to do this all in one go it would look something like this before optimization:

Conversion

static String getLookupName(String crossObjectReference)
{
    // would need to think about this more if there are managed packages
    return crossObjectReference.endsWith('__r') ?
        crossObjectReference.replace('__r', '__c') :
        crossObjectReference + 'Id';
}

Helper Class

class Parser
{
    List<String> path;
    Schema.SObjectType type;
    public Parser(Schema.FieldSetMember member, Schema.SObjectType type)
    {
        this.path = member.getFieldPath().split('.');
        this.type = type;
    }

    public Schema.DescribeFieldResult getDescribe()
    {
        // could possibly make this recursive
        while (path.size > 1)
        {
            traverse();
        }
        return describe(path[0]);
    }

    void traverse()
    {
        if (path.size() == 1) return;
        String lookupName = getLookupName(path.remove(0));
        Schema.DescribeFieldResult describe = describe(lookupName);
        this.type = describe.getReferenceTo[0];
        // this would get a lot more hairy if we want to deal with polymorphic lookups properly
    }

    Schema.DescribeFieldResult describe(String field)
    {
        return type.getDescribe().fields.getMap()
            .get(field).getDescribe();
    }
}

Putting it all together

public static List<Schema.DescribeFieldResult> convertFields(List<Schema.FieldSetMember> members, Schema.SObjectType type)
{
    List<Schema.DescribeFieldResult> describes = new List<Schema.DescribeFieldResult>();
    for (Schema.FieldSetMember member : members)
    {
        describes.add(new Parser(member, type).getDescribe());
    }
    return describes;
}
1

I realize this is an older post, but I figured out a way to get at the DescribeFieldResult from the FieldSetMember in VisualForce and Apex assuming you know the name of the object. You can get it by using the FieldPath of the FieldSetMember. In Apex it looks like this:

Schema.DescribeSObjectResult res = Schema.getGlobalDescribe().get('objName').getDescribe(); 
Map<String, Schema.FieldSet> fieldSetMap= res.fieldSets.getMap();  
Schema.FieldSet fs = fieldSetMap.get('fieldsetname');
for(Schema.FieldSetMember fsm : fs.getFields())
{System.debug(res.fields.getMap().get(fsm.getFieldPath()).getDescribe().RelationshipName);}   

I am using it in Visualforce to get the name of the related record of a lookup field so I can display it like so:

{!objectRef[$ObjectType['objectName'].fields[f.fieldPath].RelationshipName].Name)}
2
  • It's indeed old but still unsolved. Could you please provide a more detailed example as I don't get it. Your Apex code snippet is not valid and doesn't compile. In you your VF code I do not get a) where is should take the objectName from b) why I need RelationshipName . – Robert Sösemann Mar 15 '17 at 12:59
  • 2
    I have updated the example, but unfortunately I misunderstood what you were trying to do. In my use case I am trying to get the value of the name for a lookup field instead of the Id. I am working on a dynamic way to replace lookup fields with a text field and JavaScript type-ahead functionality. I see the problem you are having now. The method I am using fails if you used a nested field, because the nested field does not exist in the field map, just like you experienced. – Chris Byrom Mar 15 '17 at 21:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.