Subscribe

Appirio RSS Feed
Subscribe with Bloglines

Add to Google
Subscribe in NewsGator Online

Community

Appirio Technology Blog

Showing posts with label Visualforce. Show all posts
Showing posts with label Visualforce. Show all posts

Friday, November 14, 2008

Learning Apex: Display Multi-Object Data in Tables Easily with Apex Dummy Classes

Will Supinski

Creating tables in Visualforce is easy. Provide a list of Objects to display and define various columns that access different items in each Object. Easy. Things become tricky when one needs to display data from more than one object in a table. To solve this problem one need only define a dummy class to hold all the relevant data. This article will detail such a process.

Let us begin by inspecting the syntax of a simple Visualforce page that displays a table:

<apex:page controller="TrainingController ">
   <apex:pageBlock title="Users">
      <apex:pageBlockTable value="{!Users}" var="item">
         <apex:column value=”item.Name”/>
      </apex:pageBlockTable>
   </apex:pageBlock>
</apex:page>

public class TrainingController
   {
      public User[] getUsers()
      {
          return [select Name, Id from User];
      }
}

The above code will print out all the names for users returned by getUsers() in a shiny new table. This is easy to do without any special technique.

Consider a slightly more complex situation. You are building a Learning Management System that associates Users with Transcripts and TrainingPaths. You create a Transcript and TrainingPath custom object that each have a reference to a User defined as Trainee__c. Now you want to display each trainee in a table with the associated TrainingPath name and Transcript percentComplete field. But, how can we display three different objects within the same table? This is the question answered through the creation and use of dummy objects.

An incorrect approach to solving this issue is to create apex methods that query the objects and then call these from individual columns. Unfortunately, life is not that easy as this solution is not scalable because the number of queries would be proportional to the number of entries in the table. As soon as the table grows the governor limits will be met and your page will fail to load.

A working solution is the creation of apex dummy classes. The idea of dummy classes is that we create an apex class with the sole purpose of providing access to more than one object. Check out the dummy class below:

public class TrainingPathDummy
{
   public Training_Path__c tp { get; set; }
   public Transcript__c transcript { get; set; }
   public User trainee { get; set; }
   public TrainingPathDummy(Training_Path__c tp1, Transcript__c trans1, User trainee1 )
   {
      tp = tp1;
      transcript = trans1;
      trainee = trainee1;
   }
}

This dummy class has a member variable for each of the data objects we want to display in our table. Notice that the constructor has a parameter for each of the class variables. These will be passed in from the controller so that no queries within the dummy class. A list of these TrainingPathDummy classes can be iterated over in the pageBlockTable and its member objects can be accessed in the table easily as seen below:

<apex:page controller="TrainingController ">
   <apex:pageBlock title="Users">
      <apex:pageBlockTable value="{!TrainingPathDummys}" var="dummy">
         <apex:column value=”dummy.trainee.Name”/>
         <apex:column value=”dummy.tp.Name”/>
         <apex:column value=”dummy.transcript.PercentComplete__c”/>
      </apex:pageBlockTable>
   </apex:pageBlock>
</apex:page>

The Controller class must do all the heavy lifting of querying the data and forming it into dummy classes. Populating the list of dummy classes only takes 3 queries regardless of the size of the table. Governor safe and mother approved!

public class TrainingController
{
   public User[] getUsers()
   {
      return [select Name, Id from User];
   }  
   public Transcript__c[] getTranscripts()
   {
      return [select Name, Id, PercentComplete__c from Transcript__c];
   }

   public TrainingPath__c[] getTrainingPaths()
   {
      return [select Name, Id from TrainingPath__c];
   }
   public TrainingPathDummy[] getTrainingPathDummys()
   {
      TrainingPathDummy[] result = new TrainingPathDummy[]();

      //query for all the data
      User[] allUsers = getUsers();
      Transcript__c allTranscripts = getTranscripts();
      TrainingPath__c allTPs = getTrainingPaths();

      //find all the related data and put into dummy class
      for(User u: allUsers)
      {

         //get the related Transcript
         Transcript__c curTrans;
         for(Transcript__c trans: allTranscripts)
         {
            if(trans.Trainee__c == u.id)
            {
               curTrans = trans;
               break;
            }
         }

         //get the related TrainingPath
         TrainingPath__c curTrainingPath;
         for(TrainingPath__c tp: allTPs)
         {
            if(tp.Trainee__c == u.id)
            {
               curTrainingPath = tp;
               break;
            }
          }

         //create the Dummy class and add to the result list
         result.add(new TrainingPathDummy(u, curTrainingPath, curTrans);
   }
   return result;
}

Using Dummy classes is a useful skill for displaying data logically while keeping the total number of queries low. Add this method to your developer toolbox today!

Tuesday, September 23, 2008

Page breaks in Visualforce PDF templates

Kyle
Roche


The Visualforce page component defines a renderAs attribute that supports certain content converters. This is extremely useful when automatically printing forms, receipts, reports, etc. Often, we're asked to create nicely formatted forms that span multiple pages. If you leave the control of page breaks to the browser unexpected things can happen. This is an easy solution to solve with some basic CSS. You can use the page-break style properties to control where the browser will insert a page break. The Force.com PDF content converter will carry that over to the PDF.

Here's the basic code to demonstrate how this works. Create a new Visualforce Page called MultiPagePDF. Add the following code to the page:

<apex:page renderas="pdf">
<div style="page-break-after:always;">
This is page one
</div>
<div style="page-break-after:always;">
This should be rendered as page two
</div>
And, finally... page three
</apex:page>

9-14-2008 4-24-54 PM This should yield something like this illustration when rendered. Some natural extensions to this posting would be to dynamically insert these into the page. Inserting <div> tags and binding the style to an APEX property could be one way to accomplish this. You would pass back a blank style in some cases and return a string with the value of "page-break-after:always" for <div> sections where a break is needed.

As a quick side note, you can get a bit more advanced with the Page formatting via CSS. The following snippet shows you have to switch the page layout to landscape and add page numbers to your Visualforce page. This was found in the Case History Timeline example.

@page {
/* Landscape orientation */
size:landscape;

/* Put page numbers in the top right corner of each
page in the pdf document. */
@top-right {
content: "Page " counter(page);
}
}

Monday, September 15, 2008

Complementing Visualforce - Girafa Thumbnail Service

Kyle
Roche


There are so many technologies out there to complement your Salesforce.com projects. In a previous posting I showed you how to leverage Google's Geocoding API from within your APEX classes. In this example, let's take a look at something more useful in the UI Layer.

It's pretty typical in projects with heavy Visualforce development to create a custom search form. Recently, I was working on a project where we created a custom search form for the Account object. Instead of showing the Account's logo image, we were thinking it would be a cool enhancement to display a thumbnail to the Account's website. You could use services like Amazon's Alexa Site Thumbnail Service (as shown in the APEX Language Reference). However, most of these aren't free. After some Googling, I stumbled on the Girafa Thumbnail Service, which offers a free service to those who use less than 2000 images requests per day (200 request per day at the time of this writing. Please check girafa for updated daily limits).

Let's get started. Create a Visualforce page called GirafaThumbnail and a controller called GirafaThumbnailController. In your controller add the following APEX Property.

public string GirafaUrl
{
get
{
if (GirafaUrl == null)
{
string algorithmName = 'MD5';
string signatureKey = 'your signature key here';
string clientId = 'your client id here';
string siteUrl = 'http://www.appirio.com/';
string inputString = signatureKey + siteUrl;
Blob myDigest = Crypto.generateDigest(algorithmName, Blob.valueOf(inputString));
string myDigestString = EncodingUtil.ConvertToHex(myDigest);
integer myStartingPosition = myDigestString.length() - 16;
integer myEndingPosition = myDigestString.length();
string mySubString = myDigestString.substring(myStartingPosition, myEndingPosition);
string myUrl = 'http://scst.srv.girafa.com/srv/i?i=' + clientId + '&s=' + mySubString + '&r=' + siteUrl;
return myUrl;
}
return GirafaUrl;
}
set;
}

Let's break this down by first understanding how girafa thumbnail service works. There are a few basic steps to generating the URL for your thumbnail. Girafa's thumbnail images are embedded using the <img> tag. The call is formatted as follows:

http://scst.srv.girafa.com/srv/i?i=<client ID>&s=<signature>&r=<site URL>

client ID is your Girafa Client ID. It is supplied when you register your account. The site URL is the URL of the website for which you would like to generate a Thumbnail. In our example http://www.appirio.com

The signature authenticates your request and is generates using the following steps:

1) Concatenate your secrete key (chosen when you create your account) and the Site URL

2) Calculate the MD5 Checksum of the concatenated string.

3) The signature is the 16 least significant hexadecimal digits of the MD5 checksum.

In our method we set the variables we'll need to generate the Image call then we use the Crypto class' generateDigest() method to calculate the MD5 checksum of our concatenated string. Some basic string manipulation returns the 16 character substring and we put our URL together to return to our caller.

In your Visualforce page add an image tag to see the results. Bind the src attribute of the <img> to our APEX Property. <img src="{!GirafaUrl}"></img>. You should see something along the lines of the following illustration.

9-14-2008 5-52-59 PM

Friday, July 25, 2008

Extending Visualforce's UI - Ext JS DataGrid


Roche
In this posting we're going to use the Ext JS library to build out a custom DataGrid in a Visualforce page. Ext JS is a JavaScript library for building richer UI layers with out the need for plug in technologies. Ext JS has some fantastic UI widgets and Open Source licenses are available.


This technique will use the Simple Data Store. In future postings we'll build on this with examples using JSON and other technologies. The first step is to download the latest version of the Ext JS SDK. We're going to upload the archive as a Static Resource so we can reference it from within our Visualforce application. Remember, there's a 5MB per file limit on Static Resources so make sure you remove the sample directory from the SDK before trying to upload it as a Static Resource. Your upload resource should look like this:

StaticResourcesReferencing a Static Resource
Static Resources can be referenced by using the $Resource global variable. Archives are especially interesting because you can reference the full path to a file within an archive saving you countless effort organizing your uploads. We'll be referencing the following resources for this example.

StyleSheet: /ext-2.1/resources/css/ext-all.css
JavaScript: /ext-2.1/adapter/xt/ext-base.js
JavaScript: /ext-2.1/ext-all.js

Creating the Visualforce Page
First, make sure you have development mode enabled. Setup | My Personal Information | Personal Information | Development Mode. Create a new Visualforce page by redirecting your browser to http://server.salesforce.com/apex/ExtJs_DataGrid_Part1. Follow the prompt to create your page. Development mode enables two things in your org. First, you now have the ability to create a page via the URL, as you've just done. Secondly, you now have the ability to edit Visualforce pages from within your browser. In the bottom left of the browser click on Page Editor to open the Visualforce Editor. Add the following code to reference our Static Resources with our Ext JS library.

<link rel="Stylesheet" type="text/css" href="{!$Resource.ExtJs}/ext-2.1/resources/css/ext-all.css" />
<script type="text/javascript" src="{!$Resource.ExtJs}/ext-2.1/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="{!$Resource.ExtJs}/ext-2.1/ext-all.js"></script>

Click Save. Our page is now referencing the three static resources within the archive we uploaded. Note the use of the $Resource variable in our data binding calls.

Gathering Some Sample Data
Ext JS' "Simple Data Store" is built by constructing a string based Array which we'll bind our DataGrid. Let's create a customer controller to retrieve the data for our Visualforce page. In the Page Editor change the <apex:page> component to read as follows.

<apex:page sidebar="false" controller="ExtJSDataGrid1Controller">

You will see an option above the toolbar in the Editor to create a new APEX Class. After clicking that link you should see a new button next to Page Editor called Controller. Open the code for the Controller and paste in the following. Note the use of the Apex Property in place of the traditional getter and setter methods. This is new to Summer 08.

public class ExtJSDataGrid1Controller {
public List<Contact> myContacts {
get {
if (myContacts == null) {
myContacts = [SELECT Id, FirstName, LastName FROM Contact LIMIT 10];
}
return myContacts;
}
set;
}
}

Adding Ext JS to our Visualforce Page
Now that we have our SOQL query returning 10 Contact records we're going to add the JavaScript to generate our Ext JS DataGrid. Paste the code below into the Page Editor. Note our use of the <apex:repeat> component to build out our DataStore. Typically, the use case for the <apex:repeat> component would be to build out repeating UI elements. In this situation we're using it to build out our <script> for the rendered page.

<script type="text/javascript">
Ext.onReady(function(){
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
var myDataString = 'var myData = [ ';
<apex:repeat value="{!myContacts}" var="con" id="ContactRepeat">
myDataString += "['{!con.Id}','{!con.FirstName}','{!con.LastName}'],";
</apex:repeat>
myDataString += "['','',''] ];";
eval(myDataString);
var store = new Ext.data.SimpleStore({fields:[{name:'ID'},{name:'FirstName'},{name:'LastName'}]});
store.loadData(myData);
// CREATE THE GRID
var grid = new Ext.grid.GridPanel({store: store, columns: [
{id: 'ID', header: "ID", width: 50, sortable: true, dataIndex: 'ID'},
{id: 'FirstName', header: "First Name", width: 150, sortable: true, dataIndex: 'FirstName'},
{id: 'LastNme', header: "Last Name", width: 150, sortable: true, dataIndex: 'LastName'}
],stripeRows:true, autoExpandColumn: 'ID', height: 500, width: 1000, title: 'MY EXT JS CONTACT LIST'});

grid.render('myContactList-grid');
grid.getSelectionModel().selectFirstRow();
});
</script>

Don't Forget the DataGrid

Add the following <div> tag and click Save to view your new Ext JS driven DataGrid.
<div id="myContactList-grid"></div>


ExtJSDataGrid_Part1_Complete

Extending Visualforce's UI - Series Intro

Kyle
Roche


Welcome to the first in an on-going series of postings exploring the several approaches that are available for extending the Visualforce UI using different sets of 3rd party components. We'll look at technologies like Flex, Ext JS, YUI, and Google's Chart API to name a few.

Overview of Visualforce
Visualforce allows you to abstract the user interface layer from your standard Salesforce org and create something completely unique. Visualforce is the gateway to PaaS on the Force.com platform. Visualforce is built on the MVC Design pattern and leverages APEX define UI behaviors and navigation routines.

Extending Visualforce's UI Layer
In many cases the standard Visualforce UI elements available at GA don't meet every need. Instead of reverting to client side technologies and making calls back through the AJAX Toolkit we're going to walk you through some techniques to integrate 3rd party UI libraries and still leverage the server side power of Visualforce!

Static Resources in Visualforce
With Summer 08, we have a new kind of Salesforce storage designed specifically with Visualforce in mind, called Static Resources. You can upload files to Static Resources via Setup | Develop | Static Resources. Libraries or files uploaded to Static Resources can become items that you reference in your Visualforce pages. Things like stylesheets, JavaScript, images and even archives can be linked to through the $Resource global variable. For more information on Static Resources see the Visualforce Developer's Guide. Organize your Static Resources by compiling the items needed for your Visualforce Application into archive files (Remember, there is a 5MB per file limit). Visualforce can bind to files within the archive so there's no need to upload each file individually!

Stay tuned for our next posting where we'll integrate a DataGrid from Ext JS into a Visualforce Page.