Saturday, December 18, 2010

Visualforce / Apex Introduction

This is the recording of the session I presented last week at Dreamforce 2010 (Salesforce.com biggest event). It is a great introduction for developers (C#, Java, PHP, ...) who want to create "native" applications on the Force.com platform (Visualforce, Apex) and work with the Cloud Computing leader.  

Sunday, May 17, 2009

Formating Page Created using <apex:page RenderAs="PDF">

VisualForce allows you to create PDF documents, but did you know those files can be easily manipulated with CSS, for example you can break a document on different pages, you can set footers and headers, you can set the page size, you can add page numbering…

You can find a very good document on how to use CSS to format PDF files here

This page creates a PDF file that:

  • Users Letter as the paper size
  • Has margins of 1/4 centimeters
  • Has a title on every page
  • Every page shows the page number in this format (page # of #)
  • Control what content goes on each page.
VisualForce Page:
<apex:page renderAs="PDF">
    <style>
        @page {
            size: letter;
            margin: 25mm;
            @top-center {
                content: "Sample";
            }
            @bottom-center {
                content: "Page " counter(page) " of " counter(pages);
            }
        }
        .page-break {
            display:block;
            page-break-after:always;
        }
        body {
            font-family: Arial Unicode MS;
        }
    </style>
    <div class="page-break">Page A</div>
    <div class="page-break">Page B</div>
    <div>Page C</div>
</apex:page>

How to set up a VisualForce page to edit multiple rows at the same time?

This code explains how to build a simple page that allows you to edit several records at the same time. The code builds this table:

You can edit any email, but only those marked with the checkbox will be saved on the database once the “Save” button is clicked, additionally there is a link on each row that will navigate to the edit page and fully edit the record. This is not a very good user interface, but allows me to demonstrate some techniques.

VisualForce Page:

<apex:page controller="MultiRow" >
    <apex:form >
        <apex:pageblock >
            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!Save}" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="1">
                <apex:dataTable value="{!Contacts}" var="c" border="1" rowClasses="odd,even" styleClass="tableClass" cellpadding="3">
                    <apex:column >
                        <apex:facet name="header">Actions</apex:facet>
                        <apex:inputCheckbox value="{!c.Checked}"/>
                        <apex:commandLink value="Full Edit" action="{!URLFOR($action.Contact.Edit, c.ID)}" target="_blank" />
                    </apex:column>
                    <apex:column >
                        <apex:facet name="header">Name</apex:facet>
                        <apex:outputText value="{!c.Name}"/>
                    </apex:column>
                    <apex:column >
                        <apex:facet name="header">Email</apex:facet>
                        <apex:inputText value="{!c.Email}" />
                    </apex:column>
                </apex:dataTable>
            </apex:pageBlockSection>
        </apex:pageblock>
    </apex:form>
</apex:page>
Controller:
public class MultiRow {
    public List<multiRowContact> Contacts { get; set; }

    public MultiRow() {
        LoadData();        
    }

    public PageReference Save() {
        for (multiRowContact MRC : Contacts) {
            MRC.Save();
        }
        LoadData();
        return null;
    }
    private void LoadData() {
        Contacts = new List<multiRowContact>();
        for (List<Contact> cs : [SELECT c.ID, c.Name, c.Email FROM Contact c WHERE c.AccountID = '0018000000OdcOt']) {
            for (Contact c : cs) {
                multiRowContact MRC = new multiRowContact();
                MRC.ID = c.ID;
                MRC.Checked = false;
                MRC.Name = c.Name;
                MRC.Email = c.Email;
                Contacts.add(MRC);
            }
        }
    }

    private class multiRowContact {
        public String ID { get; set; }
        public String Name { get; set; }
        public String Email { get; set; }
        public Boolean Checked { get; set; }
        public void Save() {
            if (Checked) {
                System.debug('Saving...ID: ' + ID);
                Contact c = [SELECT c.Email FROM Contact c WHERE c.ID = :ID LIMIT 1];
                c.Email = Email;
                update c;
            }
        }
    }
}

URLFOR() explained

Although this is a very useful function in Salesforce.com, it is not properly documented.

Few days ago, I found a very good blog that explains this function, I have decided to summarize Sam Arjmandi’s article, but for full details please visit his article here.

URLFOR function returns a relative URL using this syntax:

{!URLFOR(target, id, [inputs], [no override])}
Target: Action, s-control or static resource.
Id: Resource name (string type) or record ID (depends on the “target”).
Inputs: Additional parameters passed. Format: [param1="value1", param2="value2"]
No override: A Boolean flag. Set to true if to display a standard Salesforce page regardless of whether you have defined an override for it elsewhere. (default false)

So, how to use this function for files and folders ?

Resource file: URLFOR($Resource.LogoImg)
Resource zip file or folder: URLFOR($Resource.CorpZip, 'images/logo.gif')

But equally important, is that the URL for actions that can be performed on custom and standard objects can be easily found using this function. These actions are implemented by all objects:

View record: URLFOR($Action.Account.View, account.id)
Create new record: URLFOR($Action.Account.New)
Edit record: URLFOR($Action.Account.Edit, account.id)
Delete record: URLFOR($Action.Account.Delete, account.id)
View List: URLFOR($Action.Account.Tab, $ObjectType.Account)

Note that some objects support other additional actions; for example Contact also supports "Clone" and Case also supports "CloseCase" action. To find out which action can be invoked on a particular object, check the buttons and links which can be overridden for that object. For standard objects go to Setup > App Setup > Customize > Desired Standrd Object > Buttons and Links and you will see a page like this:

Just use the name of the function like this: URLFOR($Action.Object.Name, Object.ID)

Saturday, May 16, 2009

<apex:inputCheckBox> OnChange vs. OnClick Events

VisualForce allows most of its tags to react to JavaScript events, and they are usually quite straightforward and easy to implement. But, there are few events that can be tricky…

One of them, is the OnChange event for the <apex:inputCheckbox> tag. When a checkbox is checked or uncheck it generates the OnChange event, but only after the user selects a different input element in the page, after the checkbox loses its focus.

A better user experience could be achieved if the checkbox fired its event without waiting for the focus to be lost. This can be easily achieved using the OnClick event:
VisualForce code:

<apex:inputCheckbox onClick="{!SomeMethod}" />

Governor Limits for multi-tenant communities

I don’t like rules, especially when I am caught by the cops on the highway going over the speed limit, on the other hand I’m glad people stop on red lights and drive on the correct side of the road.

There are some laws that are required to prevent chaos. Can you imagine if people could drive on the roads as fast, in any direction and in any vehicle they pleased? Imagine being run over in a red light by a “monster truck” just because they did not want to wait? Or having to avoid oncoming traffic in the lane you are driving? There has to be some order and some rules to protect our rights in the communities we live.

Fortunately, there are rules, but usually those who do not follow them (even due to ignorance) are heavily fined. In a perfect society, we would be politely reminded if any of our actions could affect other community members and possibly prevent us from doing those actions that could affect others.

The applications we develop for salesforce.com run on a multi-tenant community, and we have rules that protect us from other community member’s actions, and to protect them from our actions. These rules are collectively known as Governor Limits!

Different Document Types

You already know that Salesforce.com allows you to easily create web pages to display information from your objects, but did you know you can also create other types of documents quite easily?

Two formats are currently supported: Microsoft Excel and Acrobat Reader (PDF).

These properties for the <apex:page> tag will create an Excel document called “Cases.XLS” with the contents of your page:

<apex:page contentType="application/vnd.ms-excel#Cases.xls" cache="true">
The cache=”true” property is quite important, especially when the user browses your ORG with Microsoft Internet Explorer.

These properties will create an Acrobat Reader document called “Cases.pdf” with the contents of your page:

<apex:page contentType="application/x-download#Casessomedocument.pdf" renderas=”PDF” >
Note: Your page should not have <apex:input*> tags. First of all, it does not make sense to have these tags if the forms are not to be posted back to Salesforce.com. Second, the rendering of these tags may not be as expected. But, it is quite valid to use links.