Sunday, November 11, 2012

Strange behaviour of apex:column

Let's say you have a custom field, say Age, on a custom object, say Artist, which is a numeric field with 0 decimal places.  If you want to display it in a table showing a list of artists, normally you would do something like this:


<apex:page standardController="Artist__c" recordSetVar="artists">
<apex:pageBlock >
  <apex:pageBlockTable value="{!artists}" var="c">
    <apex:column>
      {!c.Name} 
    </apex:column>
    <apex:column>
      {!c.Age__c}
    </apex:column>
</apex:pageBlockTable>
</apex:pageBlock>  

However, in the display you'll find out your Age column is displayed as a field with 1 decimal place.  (Interestingly, I looked at the NumberOfEmployees field, a numeric field in the standard Account object, and it does not have that problem.)  It can be understood because after all, all numeric fields in Salesforce are decimal fields.  (If you go back to the set up menu and create a field, you only specify a Numeric field and then define the number of decimal places.  So that means Salesforce does not distinguish between a decimal field and an integer field.  All numeric fields are decimal fields.)

So to circumvent that, all you need to do is to use the Round function.

    <apex:column>
      {!Round(c.Age__c, 0)}
    </apex:column>


Now, there is a value attribute for <apex:column> which you can also use.  So the above can be written as:
    <apex:column value="{!c.Age__c}">
       
Well, what do you know.  This time, the Age is displayed properly with no decimal points.  Not only that, the column, via the use of value attribute, will display the column header.

So, again, with this code,

<apex:page standardController="Artist__c" recordSetVar="artists">
<apex:pageBlock>
  <apex:pageBlockTable value="{!artists}" var="c">
    <apex:column >
      {!c.Name} 
    </apex:column>
    <apex:column >
      {!c.Age__c}
    </apex:column>
    <apex:column >
       {!Round(c.Age__c, 0)}
    </apex:column>
                
    <apex:column value="{!c.Age__c}"/>  <!-- this displays the Age correctly -->
                
  </apex:pageBlockTable>
</apex:pageBlock>    
</apex:page>


you'll get this:

Notice that when you use the value attribute, the column header is automatically displayed.

Now, what if the field has some decimal places?

Let's say we also have a Height field with 3 decimal places after the decimal point.  Let's also say for simplicity, all male artists are 1.80m tall and all female artists are 1.814m tall.

If you replace all the Age__c above with Height__c, you'll see a new table.  This time, however, worse yet, you see 1.8 and not 1.800 for the male artists.  This time even the Round function used in the second height column does not help matter.  The code is this,


<apex:page standardController="Artist__c" recordSetVar="artists">
<apex:pageBlock>
  <apex:pageBlockTable value="{!artists}" var="c">
    <apex:column >
      {!c.Name} 
    </apex:column>
    <apex:column >
      {!c.Height__c}
    </apex:column>
    <apex:column >
       {!Round(c.Height__c, 3)}
    </apex:column>

    <apex:column value="{!c.Height__c}"/>  <!-- again, this displays the Height correctly -->
                             
  </apex:pageBlockTable>
</apex:pageBlock>    
</apex:page>


and this is the screen display.


But once again, the value attribute for <apex:column> shows the correct answer.

Now, finally, to the part that really got me into writing this article.  From the above, you may feel that the value attribute is the right way to go because it seems to give the most desirable display of field values.  Now, what if you want to round the column so it only shows 2 decimal places?

Sure, wrap your formula expression for the value attribute with the Round function call, so the last line of the code is:

    <apex:column value="{!Round(c.Height__c, 2)}"/>

Let's run it!

Oh no, an error!


There is no syntax error for sure.  You know Salesforce won't even let you save your code unless it's syntactically correct.  The above change saves successfully.  The error really does not make any sense.  This to me looks like a bug in Salesforce.

With my experimentation, to successfully display the value correctly, you may still want to stay away from the value attribute.  Instead, make use of a combination of <apex:outputText> and <apex:param> to format your data.  This is the final code (Note:  you will have to use the headerValue attribute to specify the column name this way).

<apex:page standardController="Artist__c" recordSetVar="artists">
<apex:pageBlock>
  <apex:pageBlockTable value="{!artists}" var="c">
    <apex:column >
      {!c.Name} 
    </apex:column>
    <apex:column >
      {!c.Height__c}
    </apex:column>
    <apex:column >
       {!Round(c.Height__c, 3)}
    </apex:column>

    <apex:column value="{!c.Height__c}"/>  <!-- again, this displays the Height correctly -->
                    
    <apex:column headerValue="Height Column">
      <apex:outputText value="{0, number, #0.00}">
        <apex:param value="{!c.Height__c}"/>
      </apex:outputText>
    </apex:column>
                                
  </apex:pageBlockTable>
</apex:pageBlock>    
</apex:page>

and this is the final output.  The last column is what I really want.



No comments:

Post a Comment

Please leave a comment.