Salesforce API documentation could be better with API versions

Once again I found a nice, no, necessary feature. When searching for RecordType-IDs in Apex, you could either query for them with SOQL (burning away the precious number of statements) OR you could just ask the schema.

With List<RecordTypeInfo> contactRTs = Schema.SObjectType.Contact.getRecordTypeInfos() you can get all available RecordTypes for this Object. With contactRTs[0].getName() you can get the label of the record type.

The label. This may be dependent on the language of the user, so it’s utterly useless in code. But there is also contactRTs[0].getDeveloperName() – yay! However, the documentation never states which is the minimum API needed for a function call, and this is absolute crap. Why not just add a line with the API-version? Otherwise you may get errors, which contradict the documentation.

Yes, I know that the Summer`18 release is not far now, so in this case it means that it was a bit more than a week before I can use this needed feature. But it cost me quite some time – checking if I had a typo, if I misread … and then finally a search for the release notes with this function. With the API version in the docs, this would have been a matter of minutes…

Salesforce: $Component-merge fields behaving unexpectedly

So I was writing a slightly complicated form validation in Javascript. Therefore I needed access to the values of all fields of an <apex:form>. But worse, some fields were shown conditionally.

So I assumed that the validation would merely need to check whether the fields existed, as a conditional rendering does not add the fields to the DOM (in contrast to hiding them with display: none). So my Visualforce page looked something like this:

<apex:page controller="ConditionalRerenderController">
    <apex:form>
        Click me
        <apex:inputCheckbox value="{!condition}" id="firstId">
            <apex:actionSupport event="onclick" rerender="conditionalBlock"/>
        </apex:inputCheckbox><br/>
        <apex:pageBlock id="conditionalBlock">
            <apex:pageBlockSection rendered="{!condition}" columns="1">
                <apex:inputText id="secondId" value="{!stringValue}" /><br/>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

The JS to get the value of the text input field would be rather simple

var inputfield = document.getElementById('secondId');
if(inputField != null)
    alert(inputfield.value);

However, the attribute id in Visualforce does not translate directly to the HTML attribute of the same name. To make sure a produced id is in fact unique, Salesforce adds information on the context, practically making it unusable to hard-code the id in javascript.

But there is the global merge field $Component which allows to resolve the produced HTML id. So I expected this to work:

var inputfield = document.getElementById('{!$Component.secondId}');
if(inputfield != null)
    alert(inputfield.value);

But inputfield would always be null, no matter whether the checkbox had been clicked before, rendering the input field.

This is quite a problem, as it turns out this merge field is not re-evaluated outside of the block that gets re-rendered. Instead, the expression always evaluates to an empty string outside of the conditionally rendered block. So you would need to put all Javascript that needs an id of an element within the conditionally rendered block.

Or – maybe more workable – you could use class names as pseudo-IDs. If you would add

styleClass="pseudoId"

to the input-field you can access it with

var elements = document.getElementsByClassName('pseudoId');
if(elements != null && elements.length > 0) {
    var inputField = elements[0];
    alert(inputField.value);
}

Have a try, and notice how the id of the text input only appears in the conditionally rendered block.
The page:

<apex:page controller="ConditionalRerenderController">
    <apex:form>
        Click me
        <apex:inputCheckbox value="{!condition}" id="firstId">
            <apex:actionSupport event="onclick" rerender="conditionalBlock"/>
        </apex:inputCheckbox><br/>
        firstId: <apex:outputText value="{!$Component.firstId}" /><br/>
        secondId: <apex:outputText value="{!$Component.secondId}" /><br/>

        <apex:pageBlock id="conditionalBlock">
            <apex:pageBlockSection rendered="{!condition}" columns="1">
                <apex:inputText id="secondId" value="{!stringValue}" /><br/>
                secondId: <apex:outputText value="{!$Component.secondId}" /><br/>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

The controller:

public class ConditionalRerenderController {
 public boolean condition {get;set;}
 public String stringValue {get;set;}
 
 public ConditionalRerenderController() {
 this.condition = false;
 this.stringValue = 'empty';
 }
}

Installation Force.com IDE

Um die Entwicklungsumgebung für Salesforce zu installieren, muss man den Anleitungen bei developer.salesforce.com folgen. Wie leider üblich, erzählt diese Dokumentation nur die halbe Wahrheit. Zumindest bei meinen Versuchen hat es mit Eclipse 4.5 nicht funktioniert, es kam zu nicht-behebbaren Abhängigkeits-problemen.

Im Moment funktioniert es, wenn Eclipse Neon.2 (4.6.2) benutzt wird. Am einfachsten ist es, den Installer für Neon zu benutzen, da dann Eclipse IDE for Java Developers auswählen. Danach kann man der Dokumentation folgen, und es sollte funktionieren. Leider kommen ein paar der Pakete aus unsignierten Quellen, daher muss diese Installation nochmal extra bestätigt werden.