Unexpected behavior with ISBLANK and CONTAINS functions in Visualforce Page

I’ve reduced my issue to the following example:

<apex:page >
  <apex:variable var="blank" value="" />
  <p> Contains(blank, 'foo'): <apex:outputText value="'TRUE'" rendered="{!CONTAINS(blank, 'foo')}" /></p>
  <p> Not(Contains(blank, 'foo')): <apex:outputText value="'TRUE'" rendered="{!NOT(CONTAINS(blank, 'foo'))}" /></p>
  <p> NULLVALUE(blank, 'x'): <apex:outputText value="{! NULLVALUE(blank,'XXXXX')}" /></p>
  <p> BLANKVALUE(blank, 'x'): <apex:outputText value="{! BLANKVALUE(blank,'XXXXX')}" /></p>
  <p> ISBLANK(blank, 'x'): <apex:outputText value="{! ISBLANK(blank)}" /></p>
</apex:page>

Which produces:

Contains(blank, 'foo'):'TRUE'
Not(Contains(blank, 'foo')):'TRUE'
NULLVALUE(blank, 'x'):
BLANKVALUE(blank, 'x'):
ISBLANK(blank, 'x'):false

How can Contains(blank, 'foo') and Not(Contains(blank, 'foo')) both return true? Why doesn’t BLANKVALUE or ISBLANK recognize the var blank as being blank?

I took this a step further, and created this controller:

public class formulaTestController {
  public string getNullValField() { return null;}
  public string getBlankValField() {return ''; }
}

If I add this controller to the page and change the variable to <apex:variable var="blank" value="{!blankValField}" />, I get the same results as above. If I change it to <apex:variable var="blank" value="{!nullValField}" />, I get this:

Contains(blank, 'foo'):'TRUE'
Not(Contains(blank, 'foo')):'TRUE'
NULLVALUE(blank, 'x'):XXXXX
BLANKVALUE(blank, 'x'):XXXXX
ISBLANK(blank, 'x'):true 

So it appears that BLANKVALUE and ISBLANK really operate on nulls, but not on blanks. Is this expected? Especially w/r/t BLANKVALUE, as NULLVALUE also exists. And why do the Contains() and (Not(Contains()) tests still produce the same result?!

In the end, I need to reliably handle a controller value that may be blank or null, treating these as special cases in my VF logic. How can I do so?

EDIT: Per suggested answer, I tried wrapping Contains test in IF(). Note that I moved the formula into outputText’s Value to make the result explicit:

<apex:page >
  <apex:variable var="blank" value="" />
  <p> IF(CONTAINS(blank, 'foo'),true, false): <apex:outputText value="{!IF(CONTAINS(blank, 'foo'),true, false)}" /></p>
  <p> IF(NOT(CONTAINS(blank, 'foo')),true, false): <apex:outputText value="{!IF(NOT(CONTAINS(blank, 'foo')),true, false)}" /></p>
  <p> IF(CONTAINS(blank, 'foo'),'true', 'false'): <apex:outputText value="{!IF(CONTAINS(blank, 'foo'),'true', 'false')}" /></p>
  <p> IF(NOT(CONTAINS(blank, 'foo')),'true', 'false'): <apex:outputText value="{!IF(NOT(CONTAINS(blank, 'foo')),'true', 'false')}" /></p>
</apex:page>

No change:

IF(CONTAINS(blank, 'foo'),true, false):false
IF(NOT(CONTAINS(blank, 'foo')),true, false):false
IF(CONTAINS(blank, 'foo'),'true', 'false'):false
IF(NOT(CONTAINS(blank, 'foo')),'true', 'false'):false

UPDATE: As noted by @tlfu below, Salesforce is now tracking this issue. You may recognize the issue description 🙂

Answer

I observed that ISBLANK(null)=true, ISBLANK(”)=false regardless of whether bound to an SObject text field or a public String variable in the controller. Compare this to how the Apex String.isBlank() method works:

String.isBlank(null) = true;
String.isBlank('') = true;

This undocumented inconsistency between Visualforce vs. Apex behavior resulted in a tricky bug in one of my Visualforce pages where I had replaced this:

rendered="{!ISNULL(stringVar) || stringVar==''}" 

with this, because I was under the impression they were functionally equivalent

rendered="{!ISBLANK(stringVar)}"

I’ve opened a case via our partner portal account to have Salesforce weigh in on this. I’ll let you know if anything useful results.

Attribution
Source : Link , Question Author : Jason Clark , Answer Author : tlfu

Leave a Comment