2

I've reached a bit of a dead end in my latest programming endeavour. To give a brief overview I'm creating a console that houses data for four custom objects linked together loosely only by their intended purpose whilst still remaining independent.

The console simply outputs a custom list for each objects associated records, which can then be filtered by a number of variables, such as the project that owns the records, whether the records are active or not etc. Inconsequential information.

My problem comes when considering the scenario where a user may want to add a custom field to one of the custom objects (which they should be able to do). I've built the Visualforce to output the wrapper object fields statically and so my build does not allow for the dynamic adoption of any user-changes. Currently the wrapper class processes all possible fields from each object and for each field type does the necessary validation to assess whether the records field is blank or not etc. The Visualforce then assesses whether the wrapper field is null before outputting as standard. The user can select from a multi-select pick list which fields they'd like to see in the columns.

Is there anything I can do or can I take a different approach to allow for dynamic expansion of the wrapper class? I'd love their to be a simple way to perhaps assess the schema of an object and create any wrapper fields necessary based on the schema. Perhaps with pre defined rules for how to assess each field according to its Type.

The four objects share similarities in structure but have enough fields different to justify their independence. Additionally they weren't made under the same object as we liked the idea of having separate related lists on the project page for each one amongst other benefits in having separate objects. However if this is the wrong way to structure my data please let me know.

Any discussion or solution related to my problem is welcomed!

1

Here are a couple of general points on the subject...

Visualforce (and Apex) support map syntax so you can present in a basic way additional values established at runtime (e.g. obtained from describe calls or field sets or custom settings):

public class Wrapper {
    ...
    public String[] keys {get; set;} 
    public Map<String, String> extras {get; set;}
    ...
    public String[] contactFields {get; set;} 
    public Contact contact {get; set;}
    ...
}

<apex:repeat var"key" value="{!keys}">
    <apex:inputText value="{!wrapper.extras[key]}"/>
</apex:repeat>

But to get the full benefit of the metadata behind an SObject field (such as data type including parsing/formatting, picklist values, label, help text) it is best to directly use the SObject fields (as SObject also supports map-like access):

<apex:repeat var"f" value="{!contactFields}">
    <apex:inputField value="{!contact[f]}"/>
</apex:repeat>

And in Apex code there are string-based get/put methods available for any SObject too. So while you can't dynamically extend the wrapper class, you may be able to add code to it driven by data (such as lists of field names) that accomplishes the processing you require.

PS

To illustrate how code can work with a varying number of fields (including fields added by a user) this code will look at every field on a Contact object instance c:

public void doSomething(Contact c) {

    for (String f : Contact.SObjectType.getDescribe().fields.getMap().keySet()) {
        Object o = c.get(f);
        if (o instanceof String) ...
        else if ...
    }
}

and there is also API to get details of a field in a DescribeFieldResult.

  • @MattGarnett You can discover the names of the fields present on an SObject at runtime by the various means I listed and reference the value just using the string name (inside a for-each loop for each field). So if you can code the core patterns once and re-use them for new fields you will be OK. If you need additional attributes to drive the logic you can configure your code using e.g. JSON. I'll add a bit more to the answer. – Keith C Apr 13 '16 at 12:42
  • @MattGarnett The platform can supply the list of fields via the object-level describe calls and also details of each field via a field-level describe call. The base class for all custom/standard objects is SObject and that has various get/put methods that will work for any type of custom/standard object. If your logic can be 100% driven from that data you are good to go, but if you want to add random/ad-hoc logic that is a lot harder. – Keith C Apr 13 '16 at 12:55
  • Yes yes yes I see now. Perfect thanks for the added code it was very helpful. Keep forgetting apex is so similar to C# and I should just try and tackle it in a similar way! instanceof is perfect and solves the gap in my logic pretty much straight away. Thanks again. – MattGarnett Apr 13 '16 at 12:57
  • @MattGarnett And if instanceof is too coarse-grained you can get the DisplayType that distinguishes between e.g. numbers and currency values. – Keith C Apr 13 '16 at 13:39
  • @Keith_C Ahh yes perfect! This is 100% required as I pretty much use the majority of these display types. – MattGarnett Apr 13 '16 at 13:48

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.