Monday, March 21, 2011

Bug (?) with apex:actionSupport Containing apex:param

I'm encountering some unexpected behavior with apex:actionSupport and apex:param in what I thought would be a simple application.

I've created a demo of an apex:select with an apex:actionSupport component to illustrate the problem.  The source code for the demo is also available.

What I expected to happen:

  1. Change the picklist value.
  2. Observe that assignToColor matches picklistColor.
  3. Observe that displayColor matches picklistColor.

What actually happens is that nothing changes except picklistColor.

Is this a bug or is this expected behavior?  I thought that apex:param could be used with apex:actionSupport components.

Sunday, March 20, 2011

Bug with Custom Component Rerender inside apex:repeat

I seem to have run into a bug with custom components trying to rerender parts of themselves: The rerendered component is able to display updated values as text, but formula evaluations of any updated values ignore the updated values and instead use initial values.

For example: Let's say I have a component has an apex:inputText with value="{!accountName}" that rerenders the parent apex:outputPanel during an onchange event. After rerendering, a few odd things happen:

  • The apex:inputText reverts to blank control.
  • If I display {!accountName} as text, the new value appears fine.
  • Any other components that have rendered="{!NOT(ISNULL(accountName))}" are still not rendered.

An experience is worth a million words, so I've put up a demo in my sandbox.  The source code for the demo is also available.

  1. In the Lead (standalone) section, enter something into the Name field.
  2. Click somewhere else on the page.  An Ajax refresh will occur, and the Text Insertions and Output Component Renders section should correctly update to reflect the new Name value.
  3. Now, in any Lead (from List) section, enter something into the Name field.
  4. Click somewhere else on the page.  An Ajax refresh will occur.
  5. Observe two problems:  The Name field is blanked out, and the Output Component Renders section did not change.

Hopefully, Salesforce Premier Support will tell me that the problem will be fixed immediately within the next 5 business days.  Hopefully...

Comparison of null to Integer Always Returning true

I ran across an interesting phenomenon when comparing null values to Integer values on Visualforce pages: The comparison always returns true!

  1. null < 0 evaluates to true
  2. null = 0 evaluates to true
  3. null > 0 evaluates to true

It appears that it's best not to compare null values to Integers, since the result is effectively useless.

ISBLANK(String) Returning false When String.length() Returns 0

I discovered this with version 21.0 of the Salesforce API: When a String's length is 0, the ISBLANK(String) Visualforce function will actually return false instead of true.

Visualforce Developer's Guide, Version 21.0 describes the ISBLANK function as follows:

Determines if an expression has a value and returns TRUE if it does not. If it contains a value, this function returns FALSE.

A search for ISNULL in the documentation returned no real results, which makes me wonder if ISNULL has been unofficially deprecated in favor of ISBLANK.

So, it appears that the only way to know for sure whether a String input has been blanked out is to use the length method and compare it to 0.

Saturday, March 19, 2011

apex:define Tag Precedence in Visualforce Templates

I learned something interesting through trial-and-error yesterday:

If you define a set of templates where each successive template "extends" the previous template, the apex:insert tag in all previous templates are available for definition in the final implementing page.

For example, let's take take the following hierarchy of templates:
  1. SiteMasterTemplate
  2. SiteDepartmentTemplate--contains an apex:composition with template="SiteMasterTemplate"
  3. SiteProductTemplate--contains an apex:composition with template="SiteDepartmentTemplate"

Now, if we create a page called SiteSuperMotor that contains an apex:composition with template="SiteProductTemplate", our page can actually use apex:define that define apex:insert elements in SiteMasterTemplate!

Furthermore, let's say that we have apex:insert elements in both SiteDepartmentTemplate or SiteProductTemplate that share the same name attribute as an apex:insert in SiteMasterTemplate, then the SiteSuperMotor page's apex:define would only define the apex:insert in SiteMasterTemplate!

Friday, March 18, 2011

Visualforce Misinterprets Empty xmlns Attributes

For unknown reasons, Visualforce does not handle an empty xmlns attribute inside a DIV tag. Unexpected behavior will result if a DIV tag is used inside a Visualforce page with xmlns="" specified as an attribute.

If a Visualforce page that contains simple HTML is not rendering like the page from which the HTML was copied, checking for empty xmlns attributes may be the key to fixing the problem.

Tuesday, March 8, 2011

jQuery in Custom Input Components

I'm trying to write my own custom input component that updates values based on button clicks. The component idea is similar to the enhanced jQuery input components created by Joel Dietz, although far less universal in application. An example of Joel's components can be found below.

"enhancedText.component"
sfdcjqueryenhancements

"EnhancedTextController.cls"
sfdcjqueryenhancements

One trick to making the component inputs work is to factor in the quirky DOM ID's generated by Salesforce. This is addressed in the following blog post from Wes Nolte.

"VisualForce Element Ids in jQuery selectors"
The Silver Lining

To clarify Wes's post, the function is defined as follows:

function esc(myid) {
    return '#' + myid.replace(/(:|\.)/g,'\\\\$1');
}

Also, the esc function cannot be called with a literal! The String must be stored in a var first, and the var should then be passed to the esc function.

Whew! I'm not done with my custom input component yet, but I definitely see bright rays of hope.

Monday, March 7, 2011

How to Write to a Custom Component Attribute

I spent a long time trying to figure out why the following code was not working:

<apex:component id="this" controller="MySiteInputAccountIdCtrl"
selfClosing="true">

<apex:attribute name="value" type="Id"
description="Account Id to pass back to the page."
assignTo="{!accountId}"
required="true"/>

<apex:inputText id="accountIdIText"
value="{!accountId}"/>

</apex:component>

accountId was a simple property with a vanilla pair of getter and setter methods. When the component is rendered as a component like <c:MySiteInputAccountId value="{!contact.AccountId}>, contact.AccountId would not update no matter what I typed into the input field.

Several hours later, I took a look back at a custom component that worked (and was also created by me after a similar bout of confusion)... And it turns out that I was writing the input to the wrong object. The correct component markup is as follows:

<apex:component id="this" controller="MySiteInputAccountIdCtrl"
selfClosing="true">

<apex:attribute name="value" type="Id"
description="Account Id to pass back to the page."
assignTo="{!accountId}"
required="true"/>

<apex:inputText id="accountIdIText"
value="{!value}"/>

</apex:component>

I can't believe I forgot this resolution to a 3-hour frustration almost immediately... just to experience a new 6-hour frustration on the same topic. Hopefully writing this down will help me remember my lesson and avoid a third incident.