Monday, July 8, 2013

Conditional Table Cell Styling

Here is a link for a demo:

http://tcs-8demo-developer-edition.na14.force.com/blog3demo

For this blog, I am using the controller that I created for my previous blog. To see the sample code for the controller, please refer back to my previous blog. 


Here is the sample Visualforce code:

<apex:page controller="Blog2DemoController" showHeader="false">
    
    <style>
        .expTable, .expTable th, .expTable td{
        font-size:14px;
        margin:auto;
        border: 1px solid black;
        }
        
        .col2{
        text-align:right;
        }
        
        .red{
        background-color:red;
        }
        
        .blue{
        background-color:blue;
        }
        
        .yellow{
        background-color:yellow;
        }
    </style>    
    
    <apex:form >  
        <center>
            <apex:selectList value="{!selYear}" label="Year" multiselect="False" size="1" style="width:400px;" onchange="updateReports();">
                <apex:selectOptions value="{!YRoptions}"/>
            </apex:selectList>
            
            <apex:actionFunction action="{!filterYear}" name="updateReports" rerender="mainPanel">
            </apex:actionFunction>
        </center>
    </apex:form>
    
    
    
    <div id="mainPanelDiv">
        
        <apex:outputPanel id="mainPanel">          
            
            
            
            <apex:dataTable value="{!TableVal}" var="exp" styleClass="expTable" cellpadding="5px" columnClasses="col1, col2">
                <apex:column headerValue="Expense Type" value="{!exp.title}"/>
                <apex:column headerValue="Total Amount" styleClass="{!if(exp.val > 7500, 'red', if(exp.val > 2500, 'yellow', 'blue'))}">
                    <apex:outputText value="{0, number, $###,###,###.##}" >
                        <apex:param value="{!exp.val}" />
                    </apex:outputText>
                </apex:column>
            </apex:dataTable>
            
            <br/>
            
            <apex:dataTable value="{!MTableVal}" var="exp" styleClass="expTable" cellpadding="5px" columnClasses="col1, col2">
                <apex:column headerValue="Month" value="{!exp.title}"/>
                <apex:column headerValue="Total Amount" styleClass="{!if(exp.val > 7500, 'red', if(exp.val > 2500, 'yellow', 'blue'))}">
                    <apex:outputText value="{0, number, $###,###,###.##}" >
                        <apex:param value="{!exp.val}" />
                    </apex:outputText>
                </apex:column>
            </apex:dataTable>
            
            <br/>
            
            <apex:dataTable value="{!CTableVal}" var="exp" styleClass="expTable" cellpadding="5px" columnClasses="col1, col2">
                <apex:column headerValue="Company" value="{!exp.title}"/>
                <apex:column headerValue="Total Amount" styleClass="{!if(exp.val > 7500, 'red', if(exp.val > 2500, 'yellow', 'blue'))}">
                    <apex:outputText value="{0, number, $###,###,###.##}" >
                        <apex:param value="{!exp.val}" />
                    </apex:outputText>
                </apex:column>
            </apex:dataTable>
            
        </apex:outputPanel>
        
    </div>
</apex:page>


The main parts of this page are:

<style></style> section - this area is where you input the css styling. You could also link to a CSS file by using <apex:stylesheet/>

<apex:column headerValue="Total Amount" styleClass="{!if(exp.val > 7500, 'red', if(exp.val > 2500, 'yellow', 'blue'))}"> - this is the column for your table cell. In this code line, you can include a styleClass. By using an if statement, you can dynamically select a class in your CSS depending on the value for that cell.

Friday, June 7, 2013

Google Visualization and Visualforce Data Filtering and Re-rendering

Here is a link for a demo:

Re-rendering a section of a Visualforce page that includes Google Visualization and updating the data is easy by using the following:
- <apex:actionFunction>
- <apex:outputPanel>
- <apex:selectList> & <apex:selectOption>

In my example, I also have jQuery but it is not really essential. I just use it to automatically re-size the charts when the window size changes.

For the data, I am using a custom object called Expense and it will show the expenses of the current user.

The main part of the Visualforce page is this:

<apex:form >        
        <apex:selectList value="{!selYear}" label="Year" multiselect="False" size="1" style="width:400px;" onchange="updateReports();">
            <apex:selectOptions value="{!YRoptions}"/>
        </apex:selectList>
        
        <apex:actionFunction action="{!filterYear}" name="updateReports" rerender="mainPanel" oncomplete="drawChart();drawChart2();">
        </apex:actionFunction>
    </apex:form>

<apex:outputPanel id="mainPanel">
          *** this is where you put the javascript that calls the Google Visualization functions to draw the charts. This is also where you include all other visualforce codes that will be re-rendered when the action is called.
</apex:outputPanel>

  • The value for the select list comes from a getter method in the controller called getYRoptions and by using Salesforce's Select Option Class
  • I use onchange="updateReports();" in selectList to call the action in actionFunction. ActionFunction acts like a javascript function but it calls a controller method instead of a javascript function.
  • In actionFunction I call the following attributes:
    • rerender - here, I put the id of the outputPanel that will be re-rendered when the action is called
    • name - this is used by selectList to call actionFunction like it's a javascript function
    • oncomplete - this is used to call the javascript methods to re-draw the charts when the controller completes the action
By doing this, your chart will dynamically update based on the picklist value selected in the Visualforce page.

Here is the sample Visualforce code:

<apex:page controller="Blog2DemoController" showHeader="false">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    
    <apex:form >        
        <apex:selectList value="{!selYear}" label="Year" multiselect="False" size="1" style="width:400px;" onchange="updateReports();">
            <apex:selectOptions value="{!YRoptions}"/>
        </apex:selectList>
        
        <apex:actionFunction action="{!filterYear}" name="updateReports" rerender="mainPanel" oncomplete="drawChart();drawChart2();">
        </apex:actionFunction>
    </apex:form>
    
    <div id="mainPanelDiv">
        
        <apex:outputPanel id="mainPanel">
            
            <script>
                var $j = jQuery.noConflict();             
                
                // Load the Visualization API and the piechart package.
                google.load('visualization', '1.0', {'packages':['corechart']});
                
                // Set a callback to run when the Google Visualization API is loaded.
                google.setOnLoadCallback(drawChart);
                
                // Callback that creates and populates a data table,
                // instantiates the pie chart, passes in the data and
                // draws it.
                function drawChart() {
                
                // Create the data table.
                var data = new google.visualization.DataTable();
                data.addColumn('string', 'Expense Type');
                data.addColumn('number', 'Amount');
                
                <apex:repeat value="{!TableVal}" var="x" id="theRepeat">
                    data.addRow(["{!x.title}",{!x.val}]);
                </apex:repeat>
                
                // Set chart options
                
                var width = $j(window).width();
                var options = {'title':'Expensed Amount by Expense Type',
                'width':width,
                'height':width*.5,
                'backgroundColor':'none',
                'pieSliceText':'none'};
                
                // Instantiate and draw our chart, passing in some options.
                var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
                
                var formatter = new google.visualization.NumberFormat(
                {prefix: '$', negativeColor: 'red', negativeParens: true});
                formatter.format(data, 1);
                
                chart.draw(data, options);
                }
                
                
                google.setOnLoadCallback(drawChart2);
                function drawChart2() {
                var data2 = google.visualization.arrayToDataTable([
                ['Month', 'Expenses']
                <apex:repeat value="{!MTableVal}" var="x">
                    ,['{!x.title}',  {!x.val}]
                </apex:repeat>
                ]);
                
                var width = $j(window).width();
                
                var options = {
                title: 'Monthly Total Expenses',
                hAxis:{slantedText:true, slantedTextAngle:30},
                legend:{position:'none'},
                backgroundColor:'none',
                width:width,
                height:width*.5
                };
                
                var chart2 = new google.visualization.LineChart(document.getElementById('chart2_div'));
                
                var formatter = new google.visualization.NumberFormat(
                {prefix: '$', negativeColor: 'red', negativeParens: true});
                formatter.format(data2, 1);
                
                chart2.draw(data2, options);
                }
                
                function loadingMessage(){
                $j('#mainPanelDiv').css('display', 'none');
                }
                
                function endLoadingMessage(){
                $j('#mainPanelDiv').css("display", "block");
                }
                
                
                $j(window).resize(function() {
                drawChart();
                drawChart2();
                });
                
            </script>    
            
            <style>
                .expTable, .expTable th, .expTable td{
                font-size:14px;
                margin:auto;
                border: 1px solid black;
                }
                
                .col2{
                text-align:right;
                }
                
                #chart_div{
                margin:auto;
                }
            </style>           
            
            <apex:dataTable value="{!TableVal}" var="exp" styleClass="expTable" cellpadding="5px" columnClasses="col1, col2">
                <apex:column headerValue="Expense Type" value="{!exp.title}"/>
                <apex:column headerValue="Total Amount" >
                    <apex:outputText value="{0, number, $###,###,###.##}" >
                        <apex:param value="{!exp.val}" />
                    </apex:outputText>
                </apex:column>
            </apex:dataTable>
            
            <br/>
            
            <apex:dataTable value="{!MTableVal}" var="exp" styleClass="expTable" cellpadding="5px" columnClasses="col1, col2">
                <apex:column headerValue="Month" value="{!exp.title}"/>
                <apex:column headerValue="Total Amount" >
                    <apex:outputText value="{0, number, $###,###,###.##}" >
                        <apex:param value="{!exp.val}" />
                    </apex:outputText>
                </apex:column>
            </apex:dataTable>
            
            <br/>
            
            <apex:dataTable value="{!CTableVal}" var="exp" styleClass="expTable" cellpadding="5px" columnClasses="col1, col2">
                <apex:column headerValue="Company" value="{!exp.title}"/>
                <apex:column headerValue="Total Amount" >
                    <apex:outputText value="{0, number, $###,###,###.##}" >
                        <apex:param value="{!exp.val}" />
                    </apex:outputText>
                </apex:column>
            </apex:dataTable>
            
            <div id="chart_div"></div>
            
            <div id="chart2_div"></div>
            
        </apex:outputPanel>
        
    </div>
</apex:page>

Here is the sample controller for the Visualforce page:

public class Blog2DemoController{
    
    ID ownID;
    
    public String selYear {get; set;}
    
    public Blog2DemoController(){
        selYear = string.valueof(date.today().year());
        
        ownId = '005d00000012d9s';
    }
    
    public List<SelectOption> getYRoptions() {
        List<SelectOption> options = new List<SelectOption>();
        
        integer yr = date.today().year();
        
        Expense__c exp = new Expense__c();
        if([select Id, Date__c from Expense__c where ownerID =: ownID order by Date__c limit 1] != null){
            exp = [select Id, Date__c from Expense__c where ownerID =: ownID order by Date__c ASC limit 1];
            
            integer y = exp.Date__c.year();
            
            system.debug(exp.Date__c.year());
            
            for(integer x = yr; x >= y; x--){
                options.add(new SelectOption(string.valueof(x), string.valueof(x)));   
            }
            
            system.debug(options);
        }else{
            options.add(new SelectOption(string.valueof(yr), string.valueof(yr)));
        }
        
        
        return options;
    }
    
    public List<tableWrapper> getTableVal() {
        
        List<tableWrapper> data = new List<tableWrapper>();
        
        //double totalVal = 0;
        
        for (AggregateResult ar : [select Expense_Type__c eType, SUM(Total_Amount__c) sAmt from Expense__c WHERE CALENDAR_YEAR(Date__c) =: integer.valueof(selYear) AND OwnerId =: ownID group by Expense_Type__c])  {
            data.add(new tableWrapper(string.valueof(ar.get('eType')), double.valueof(ar.get('sAmt'))));
            //totalVal += double.valueof(ar.get('sAmt'));
        }
        
        //data.add(new tableWrapper('Total', totalVal));
        
        return data;
    }
    
    public List<tableWrapper> getMTableVal() {
        
        Map<string, string> monthMap = new Map<string,string>();
        monthMap.put('1', 'Jan');
        monthMap.put('2', 'Feb');
        monthMap.put('3', 'Mar');
        monthMap.put('4', 'Apr');
        monthMap.put('5', 'May');
        monthMap.put('6', 'Jun');
        monthMap.put('7', 'Jul');
        monthMap.put('8', 'Aug');
        monthMap.put('9', 'Sep');
        monthMap.put('10', 'Oct');
        monthMap.put('11', 'Nov');
        monthMap.put('12', 'Dec');
        
        
        List<tableWrapper> data = new List<tableWrapper>();
        
        for (AggregateResult ar : [select CALENDAR_MONTH(Date__c) d, SUM(Total_Amount__c) sAmt from Expense__c WHERE CALENDAR_YEAR(Date__c) =: integer.valueof(selYear) AND OwnerId =: ownID group by CALENDAR_MONTH(Date__c) ORDER BY CALENDAR_MONTH(Date__c)])  {
            data.add(new tableWrapper(monthMap.get(string.valueof(ar.get('d'))), double.valueof(ar.get('sAmt'))));
        }
        
        return data;
    }
    
    public List<tableWrapper> getCTableVal() {
        
        List<tableWrapper> data = new List<tableWrapper>();
        
        //double totalVal = 0;
        
        for (AggregateResult ar : [select Company__c c, SUM(Total_Amount__c) sAmt from Expense__c WHERE CALENDAR_YEAR(Date__c) =: integer.valueof(selYear) AND OwnerId =: ownID group by Company__c order by Company__c])  {
            data.add(new tableWrapper(string.valueof(ar.get('c')), double.valueof(ar.get('sAmt'))));
            //totalVal += double.valueof(ar.get('sAmt'));
        }
        
        //data.add(new tableWrapper('Total', totalVal));
        
        return data;
    }
    
    public class tableWrapper {
        public string title {get; set;}
        public double val {get; set;}
        
        //This is the contructor method. When we create a new cContact object we pass a Contact that is set to the con property. We also set the selected value to false
        public tableWrapper(string c, double v) {
            title = c;
            val = v;
        }
    }
    
    public PageReference filterYear() {
        
        getTableVal();
        getMTableVal();
        getCTableVal();
        
        return null;
        
    }
    
}






Monday, June 3, 2013

Using apex:repeat to populate Google Charts data

Here is an easy way to integrate Google Charts into your Visualforce page with a simple controller!

Here is the controller example:

public class exampleController{
    public List<tableWrapper> getTableVal() {        
        List<tableWrapper> data = new List<tableWrapper>();                
        data.add(new tableWrapper('Work', 11));
        data.add(new tableWrapper('Eat', 2));
        data.add(new tableWrapper('Commute', 2));
        data.add(new tableWrapper('Watch TV', 2));
        data.add(new tableWrapper('Sleep', 7));    
        return data;
    }    
    public class tableWrapper {
        public string title {get; set;}
        public double val {get; set;}
        public tableWrapper(string c, double v) {
            title = c;
            val = v;
        }
    }    
}

In this controller example, I am not using any salesforce objects for the data. I just created the object and the data in the controller but you can easily do the same with salesforce objects by querying the data.

Here is an example of the Visualforce page:

<apex:page controller="exampleController">
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Task', 'Hours per Day']
            <apex:repeat value="{!TableVal}" var="x">
                ,['{!x.title}',  {!x.val}]
            </apex:repeat>
        ]);
        var options = {
          title: 'My Daily Activities'
        };
        var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    <div id="chart_div" style="width: 900px; height: 500px;"></div>
</apex:page>
I used apex repeat to dynamically add the data in the javascript section to create the Google Chart. Simple and easy!

Here is the resulting chart: