0

Here's what I'm trying to do:

I have multiple Objects that are related to a Contact. In a Visualforce page, I want to create a tab for each of these related Objects; then, in their respective tabs, I want to create a table that shows values defined in a field set for each object.

I've approached this problem from a few different angles, and nothing seems to be working.

Initially, and with some success, I attempted to retrieve all related Objects from Salesforce and use the fieldLabel and relationshipName to populate the table. Something like this:

Controller:

public Map<String, String> getRelatedObjects() {
    Schema.DescribeSObjectResult result = Contact.SObjectType.getDescribe();
    Map<String, String> relatedObjects = new Map<String, String>();

    //Loop through child relationships and retrieve the label/name of our related objects
    for (Schema.ChildRelationship cr: result.getChildRelationships()) {
        Schema.DescribeSObjectResult childObject = cr.getChildSObject().getDescribe();

        //So we don't retrieve unwanted relationships, we prefix ours with 'RRP'
        //Maybe attempt to come up with a more dynamic solution in the future?
        if (childObject.Name.contains('RRP')) {
            relatedObjects.put(cr.getRelationshipName(), childObject.LabelPlural);
        }
    }
    return relatedObjects;
}

VF:

<ul class="nav nav-tabs" role="tablist">
    <apex:repeat value="{! RelatedObjects }" var="ro">
        <li class="nav-item">
            <a class="nav-link" href="#{! RelatedObject[ro] }">{! RelatedObjects[ro] }</a>
        </li>
    </apex:repeat>
</ul>
<div class="tab-content">
    <apex:repeat value="{! RelatedObjects }" var="ro">
        <div class="tab-pane" id="{! RelatedObjects[ro] }" role="tabpanel">
            <apex:dataTable value="{! Contact[ro] }" var="program">
                <!---TO DO: Link fields to fieldsets-->
                <apex:column>
                    <apex:facet name="header">Name</apex:facet>
                    <apex:outputLink value="#">{! program.Name }</apex:outputLink>
                </apex:column>
           </apex:dataTable>
        </div>
    </apex:repeat>
</div>

This worked well for creating the tabs that I need, but breaks when creating the table. It seems that <apex:dataTable> just doesn't like bracket notation, as referencing the relationship directly (with Contact.RRP_GrantPrograms__r) works, but using brackets results in an error.

Error: SObject row was retrieved via SOQL without querying the requested field: Contact.RRP_GrantPrograms__r

This is my first time working with Salesforce, so I'm not aware of all methods that are available to me. I would greatly appreciate some incite if someone could point my in the right direction?

EDIT: Added update code.

public Map<String, Contact> getRelatedObjects() {
    Schema.DescribeSObjectResult result = Contact.SObjectType.getDescribe();
    Map<String, Contact> relatedObjects = new Map<String, Contact>();

    //Loop through child relationships and retrieve the label/name of our related objects
    for (Schema.ChildRelationship cr: result.getChildRelationships()) {
        Schema.DescribeSObjectResult childObject = cr.getChildSObject().getDescribe();

        //So we don't retrieve unwanted relationships, we prefix ours with 'RRP'
        //Maybe attempt to come up with a more dynamic solution in the future?
        if (childObject.Name.contains('RRP')) {
            String relationshipName = cr.getRelationshipName();
            relatedObjects.put(childObject.LabelPlural, queryContact(relationshipName));
        }
    }
    return relatedObjects;
}

public Contact queryContact(String relationshipName) {
    String query = 'SELECT Id, (SELECT Name FROM ' + relationshipName + ') FROM Contact LIMIT 1';
    system.debug('<<<<<<' + query + '>>>>>>>');
    Contact c = Database.query(query);
    return c;
}
0

In Your code at line

 <apex:dataTable value="{! Contact[ro] }" var="program">

You are trying to access child record from master but dynamic visualforce Binding does not works like that.

Dynamic Visualforce binding is supported for standard and custom objects. Dynamic bindings take the following general form:

reference[expression]

where

reference evaluates to either an sObject, an Apex class, or a global variable

expression evaluates to a string that is the name of a field, or a related object. If a related object is returned, it can be used to recursively select fields or further related objects.

Example : {!myContact['Account'][fieldname]} But what you are trying is {!Account['Contact'][fieldname]} which is wrong. Secondly when when you are replacing Contact[ro] with Contact.RRP_GrantPrograms__r You are getting list of RRP_GrantPrograms associates with your case which you have to query like.

Contact c = [select Id, (Select Id from RRP_GrantPrograms__r) from Contact LIMIT 1];
  • Thank you, this produces the desired result. However, this only works when the FROM clause is hard-coded, even in dynamic SOQL. Contact c = Database.query('SELECT Id, (Select Name From ' + relationshipName + ') from Contact LIMIT 1'); Produces: >Error: SObject row was retrieved via SOQL without querying the requested field: Contact.RRP_GrantPrograms__r Contact c = Database.query('SELECT Id, (Select Name From RRP_GrantPrograms__r') from Contact LIMIT 1'); Does not. – NorianNyx Sep 28 '17 at 20:54
  • Can you post code ..Because Ideally it should work. did you try to debug relationshipName . – Amit Sep 29 '17 at 6:03
  • I've added the updated code, and yes, relationshipName is the correct string. – NorianNyx Sep 29 '17 at 14:32

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.