2

I have a VF Page that can be used with multiple SObject types (e.g., Account, Case, Contact). It uses a custom controller that determines the SObject type and exposes it as a property named recordType. This allows VF code in the page (or in components on the page) to dynamically show or hide content, for example:

<apex:outputText rendered="{!recordType == 'Account'}" value="..." />

This all works fine. However, instead of inline string values (e.g., 'Account'), we tried to change the code to this:

<apex:outputText rendered="{!recordType == $ObjectType.Account.name}" value="..." />

This doesn't work, and I could not find documentation of $ObjectType. properties, return types, etc., only example usage. Building some tests into the VF Page proved this:

//sample output
$ObjectType.Account.Name: Account
$ObjectType.Account.Name == 'Account': false

So $ObjectType.Account.Name can't even be compared with a literal string, but outputting it on the page ( {!ObjectType.Account.Name} ) produces a stringified result. This attempt:

<apex:outputText rendered="!recordType == TEXT($ObjectType.Account.name)" value="..." />

produced an error while saving the page that TEXT() expects a number, percent, etc, not an Object. So $ObjectType.Account.name returns an object, but attempts to add .toString() and .toString don't work (as expected on a merge property).

So, is there any way to test against $ObjectType.Account.Name? We came up with one - stashing the value in an apex variable like so:

<apex:variable var="AcctRecType" value="{!$ObjectType.Account.Name}" />

puts the string value 'Account' into the variable, allowing it to be tested. However, we use this pattern in a number of custom components, so we will need to add this variable to each one, perhaps several (the page supports multiple record types), e.g.,

<apex:variable var="AccountRecType" value="{!$ObjectType.Account.Name}" />
<apex:variable var="CaseRecType" value="{!$ObjectType.Case.Name}" />
<apex:variable var="ContactRecType" value="{!$ObjectType.Contact.Name}" />

We could also expose these names as properties on the custom controller, but that starts to feel cumbersome. Which leads me back to my original question: Is there any way to treat $ObjectType.{sobject}.name as a string for comparison within a VF mergefield?

2

Do you have to compare a field of the object? If not you could compare the object type itself.

<apex:outputText rendered="{!recordType == $ObjectType.Account}" value="..." />

where recordType would need to be the Id key prefix, e.g for account the value is '001', case the value is '500'

I think this approach is safer than using label, because the label could change at any time and break the code.

2
  • 1
    Id agree. It would be safer to get the key prefix using describe rather than compare with string literals. Account.sObjectType.getDescribe().getKeyPrefix() = '001' – techtrekker Oct 15 '12 at 6:41
  • This surprised me - I did not think you could directly compare the string '001' to the object $ObjectType.Account. More VF deep magic :) Also worth noting here, @techtrekker's apex code for getting the prefix can be translated to VF merge syntax, as $ObjectType.Account.keyPrefix. – Jason Clark Oct 19 '12 at 13:05
1

As long as your Name and Label are the same, you should be able to use the Label attribute, which returns a String

{!$ObjectType.Account.Label == 'Account'}

evaluates to true

3
  • 1
    I'd be careful of this one. Labels translate with the user locale. You might be setting yourself up for difficulties solving it this way. EN: Account, FR: Compte, ES: Cuenta, etc. – pchittum Oct 14 '12 at 23:29
  • I've added an answer that addresses this shortcoming – Daniel Blackhall Oct 15 '12 at 6:24
  • I believe these are valid concerns only if the translation workbench is enabled. But yes safer to compare sObject key prefixes. – techtrekker Oct 15 '12 at 6:39
0

Have you considered going with dynamic visualforce (VF generated from Apex)?

The level of flexibility that you seem to need could perhaps be well served by moving the logic of what to build on the page into code, as opposed to the Visualforce markup?

As far as reusability goes, you could also write this into a library of apex code that could then be easily plugged into many different pages/components.

You will also have a lot more fine grained control over logic.

Downside is that it is clunkier than just writing visualforce. But in your case you might find it worth the extra effort.

0

I think this is a Salesforce defect.

According to the $ObjectType documentation, $ObjectType.Lead.name should return a string, but as you can see if you try something like

{!$ObjectType.Lead.name + ''}

you get an error

Incorrect parameter type for operator '+'. Expected Text, received Object

showing that it is returning an object.

The same issue exists for field schema details, e.g.

{!$ObjectType.Lead.Fields.Phone.name + ''}

but works ok for

{!$ObjectType.Lead.Fields.Phone.localName + ''}

despite both Data Types being defined as strings.

0

I think that best solution is to utilize map syntax of VisualForce rendered="{!$ObjectType[recordType].Name == ($ObjectType.CampaignMember.Name)}"

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.