[SalesForce] Rendering a Conditional Format for VisualForce Table Cell

I need to render the background color of a cell based on the value in the cell. The value is retrieved from the a map generated by the controller. The background color will be one of seven colors based on the value retrieved. I have a method written that sets the value of the color as a string and takes the value of the rendered double as an arguement.

It's returning an error "Unknown property 'heatMapController.color'. I figured out from other posts in the forum about this error that the system is looking at the statement:

style="{!color(defendNTAPNum[o.id])}"

as a function instead of a method call, but how do I call the method and pass the value in? The method signature is: String getColor(Double Val)

Here is the method:

public string getColor(Double val){
    color = '';
    if(val >= 0 && val < 25){
        color='background-color:#FF0000;';
    }
    if(val >= 25 && val < 50){
        color='background-color:#FF1493;';
    }
    if(val >= 50 && val < 75){
        color='background-color:#FFB6C1;';
    }
    if(val >= 75 && val < 85){
        color='background-color:#FFFF00;';
    }
    if(val >= 85 && val < 95){
        color='background-color:#ADFF2F;';
    }
    if(val >= 95 && val < 100){
        color='background-color:#9ACD32;';
    }
    if(val == 100){
        color='background-color:#228B22;';
    }
    return color;
}

And this is how I'm calling it:

<apex:column headervalue="SitNum" style="{!color(defendNTAPNum[o.id])}">

Thank you for your feedback!

Best Answer

Visualforce's expression language doesn't support the calling of controller methods with arbitrary parameters. (In occasional circumstances you may be able to use the available map syntax to approximate this.)

The binding between Visualforce pages and controllers is primarily based on controller properties that at most can have setter and getter methods. Multiple levels of reference are supported though e.g. "Child.Parent.ParentField".

So unfortunately you have to bend your thinking to these limitations, and as @dphil suggests that generally means refactoring so that instead of your controller supplying a list of SObjects, it supplies a list of "wrapper" objects:

public class MyWrapper {
    public MySObject__c sob {get; private set;}
    public MyWrapper(MySObject__c sob) {
        this.sob = sob;
    }
    public String getStyle() {
        Decimal val = getDefendNTAPNum();
        if (val >= 0 && val < 25) {
            return 'background-color:#FF0000;';
        } else if ...
    }
    public Decimal getDefendNTAPNum() {
        return ...;
    }
}

Then your page can reference a "computed" value or just the underlying SObject field as required:

<apex:column headervalue="SitNum" style="{!w.style}" value="{!w.sob.MyField__c}">

Note that there is also a set of built in functions (including a CASE function) that sometimes can be used to implement basic conditional logic within the Visualforce expression.