function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
SteveEthosSteveEthos 

dataTable - Row level customization based on the data

Here is a problem that I have faced, and how I solved it. I am looking to see if there are other approaches:
 
I have to display a list of data.  I need to be able to customize the rows/cells of the display based on the data.  One example would be to display the text in Red if a certain condition is met.  Another would be to change the font/style/alignment based on the individual row data.
 
In a programming language like ASP .NET, I would be able to have the code behind (in Visual Force that would be the controller), be able to respond to certain events on the list object.  The one I use often in .NET is  "OnRowDataBound".  In that case the method is called for each row of data, and I get a handle to the visual objects that I can then customize.
 
In Visual Force, the Controller does not appear to have access to the VF Page.  It appears as though the relationship is one way, the VF page access attributes on the controller and calls methods for actions.
 
----------------------------------------------------------------------------
Here is a simple way to be able to accomplish it using the dataTable:
 
<apex:dataTable value="{!groups}" var="grp" >
             <apex:column styleClass="drugClassCol" >
                       <apex:facet name="header">Drug Class</apex:facet>
                        <span style="{!grp.nameStyle}">{!grp.obj.name}</span>
             </apex:column>    
</apex:dataTable>  

You can see that we created an html Span, and had the style returned from the row of data.  This way the data object can completely customize the style returned. 

----------------------------------------------------------------------------

However, you can see that there are 2 different attributes, and there is that "grp.obj.name".  The reason for this is that the SObject that we use does not and should not contain "Display code".  In the "Model View Controller" model, that means that the SObject is the Model, and the style generation is the View.  

We solve this problem by creating a SObject display object that contains the style customization logic. 

public class DrugGroupDisp
{
    private drug_group__c obj;
    public drug_group__c getObj()
    {
        return obj;
    }
    public void setObj(drug_group__c s)
    {
        obj = s;
    }

   public String getNameStyle()  

  {
        if (some condition} return 'color: red';

       return 'color: green';

    }

                   
    public void Setup(drug_group__c o)
    {
        obj = o;
    }
}

 

By having a direct reference to the original SObject, we can get access to all of its attributes, and then if needed we can made modifications and save.

the display object gives us a row level wrapper that can provide customizations that the Visual Force Page can use for rendering.

----------------------------------------------------------------------------

Here is how we load the display object:

public List<DrugGroupDisp> getGroups()
    {
         if (groups == null)
         {
             groups = new List<DrugGroupDisp>(); 
            
             for(drug_group__c groupRow : [select id, name, x1, x2, x3...   from drug_group__c])
            {
                DrugGroupDisp grp = new DrugGroupDisp();
                grp.Setup( groupRow );                                 
                groups.Add( grp);
            }     
        }   
        return groups;
    }

----------------------------------------------------------------------------

So, the controller loads the data into a list of Display objects, and the Visual Force page reads each row and access the getter methods on each row that can customize the display based on different value(s) on the SObject.

This is my solution to how to solve the problem.  Are there other approaches?  It would be great to know if there is another way! 

Hopefully sometime in the future we will have the ability for the Controllers to have more access into the rendering process for the VF Pages.

Thanks,

Steve



Message Edited by SteveEthos on 08-05-2008 12:08 PM
jwetzlerjwetzler
You can also use formulas directly on your page, like style="{!if(grp.obj.name == 'some name', 'color:red', 'color:green')}".  You could also do style="{!if(someCondition, 'color:red', 'color:green'}", where someCondition is a boolean property (or getSomeCondition is a boolean getter) in your controller.

Personally I prefer to keep the View and the Controller separated this way, but it depends on what makes more sense for your page.
SteveEthosSteveEthos

Thanks, those formulas seem like a good way for small items and simpler logic. 

For more complex logic, I like having the separate object that can share methods and have full programming capabilities.  That way we can layer the logic and share code. 

The DisplayObjects create a nice layer of encapsulation. It also prevents the VF pages from becoming too complex and hard to maintain. 

Always the balance between the different extremes: 

a) simplified architecture (putting it all in the page), but where the pages can become extremely complex

b) component architecture (separating into 'helper' and/or 'display' classes), but where it makes some of the logic a little harder to find.

Steve

MyGodItsColdMyGodItsCold
I have a column of check boxes & when a checkbox is checked or unchecked, use javascript to change the color of the row based on the new value of the checkbox & current color. - So, that's yet another angle of UI.
gireeshzgireeshz
Steve,

Just to reinforce your thinking -

We ended up doing this the exact same way as you.  As a matter of fact the idea came from another post where Ron Hess suggested creating the sObject as a wrapper just as you have done.    This seems to work well, and I dont' see much of a way around it right now.

In our case, we had to color each row based on one of the values in the row.  The potential list of values was sizeable (about 20), which made it VERY cumbersome to try and do inline in the VF page itself.  We created a getter method as you did to determine which color to use.

Also, unless I am doing it incorrectly, we had to do this at the 'column' level in VF, not for the 'row'.  so, since the report had around 20 columns, that would have been 20  'IF' statements with 20 conditions each.  Quite ugly IMHO, and very troublesome if the client suddenly decided to change his mind about which color belonged to which value.  In the way we did it, we only have to change in the getter method once and the whole page follows suit.


regards,

gireesh