Find your content:

Search form

You are here

Unexpected behavior with ISBLANK and CONTAINS functions in Visualforce Page

 
Share

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 :)


Attribution to: Jason Clark

Possible Suggestion/Solution #1

When I changed the page to be this i.e. 1) change var to be a blank field on Account and 2) AND the output of CONTAINS with TRUE, it seems to work as expected:

  <apex:page standardController="Account">
  <apex:variable var="blank" value="{!Account.Fax}" />
  <p> Contains(blank, 'foo'): <apex:outputText value="'TRUE'" rendered="{! TRUE && CONTAINS(blank, 'foo')}" /></p>
  <p> Not(Contains(blank, 'foo')): <apex:outputText value="'TRUE'" rendered="{! TRUE && 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>

I have a feeling that the functions are attuned to working with sObject fields rather than a dynamic variable (or even if a variable, at least initialised to an sObject field) in Visualforce.

Contains(blank, 'foo'):

Not(Contains(blank, 'foo')):

NULLVALUE(blank, 'x'):XXXXX

BLANKVALUE(blank, 'x'):XXXXX

ISBLANK(blank, 'x'):true

So its almost as if the output of CONTAINS is somehow messing up, although it seems to be alright after you AND it with TRUE, which in essence is just transparent and lets the actual value of it pass through.


Attribution to: techtrekker

Possible Suggestion/Solution #2

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 to: tlfu

Possible Suggestion/Solution #3

It seems that the variables declared with blank values do not really contain zero-length strings as intended.

Consider the following Visualforce page:

<apex:page>
    <apex:variable var="blank" value="" />
    <p><apex:outputText value="NOT TRIMMED: {!ISBLANK(blank)}" /></p>
    <p><apex:outputText value="TRIMMED: {!ISBLANK(TRIM(blank))}" /></p>
</apex:page>

The output of this is:

NOT TRIMMED: false
TRIMMED: true

Since using the TRIM() function inside of the ISBLANK() function returned the correct result, perhaps it's the use of variables representing zero-length strings that is broken, not the ISBLANK() function.


Attribution to: David Massad

Possible Suggestion/Solution #4

This is actually an issue with your use of <apex:variable>. According to the documentation, the value parameter is supposed to refer to an object. Think of it more as an alias than anything else, to simplify your later references. For example, after <apex:variable var="r" value="{!Custom_Object__c.Related_Object__r}"/>, you can easily refer to fields r.foo, r.bar and r.baz.

So, in your example, the blank alias is failing, so trying to use it in other functions leads to inconsistent results.


Attribution to: tomlogic
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/4397

My Block Status

My Block Content