Advanced User Interfaces - Development with the Force.com Platform: Building Business Applications in the Cloud, Third Edition (2014)

Development with the Force.com Platform: Building Business Applications in the Cloud, Third Edition (2014)

7. Advanced User Interfaces

Now that you are familiar with the basics of Visualforce, this chapter introduces features that enable you to build richer, more interactive user interfaces. The features are divided into the following sections:

Image Asynchronous actions—Visualforce has built-in, cross-browser support for Ajax behavior, without requiring you to write JavaScript code or integrate with JavaScript libraries.

Image Modular Visualforce—Visualforce has a number of features to enable you to write modular pages. You can embed static content, build pages that include other pages, define page templates, and create your own library of custom Visualforce components.

Image Dynamic Visualforce—Learn how to create Visualforce pages that can change their structure on the fly, based on administrator-maintainable declarative metadata or the results of executing Apex code.

Image Single-page applications in Force.com—Take a slight detour away from Visualforce to develop high-performance Web applications that use the latest client-side frameworks and Force.com as the data layer.

Image Introduction to Force.com Sites—Visualforce pages can be accessed by users who do not have accounts in your Force.com organization using a feature called Force.com Sites.

Image Sample application—The Services Manager sample application’s Skills Matrix is enhanced to demonstrate Ajax behavior and the use of JavaScript libraries and custom Visualforce components.


Note

The code listings in this chapter are available in a GitHub Gist at http://goo.gl/lMfqc.


Asynchronous Actions

So far, you’ve built Visualforce pages that have a simple interaction with their controller. They display data from the controller, potentially allowing the user to change it, and then submit it using an action component such as a commandButton. The action component invokes a method on the controller that returns a PageReference, navigating the user to a new page or refreshing the current page.

Visualforce actions also support more complex, asynchronous interactions with the page, commonly referred to as Ajax. Ajax is short for Asynchronous JavaScript and XML. Visualforce supports Ajax in two ways:

1. It allows actions to run in the background. The user is free to continue working with the page while Force.com processes the result. For example, a duplicate checking algorithm could examine the page while the user is inputting data, flagging duplicate records as they are discovered.

2. Actions can refresh a subset of the Visualforce page, such as a table of data, rather than the entire page. This can create a richer, more interactive experience for users and often better-performing pages.

This section explains how to add Ajax behavior to Visualforce pages. It includes the following subsections:

Image Partial page refresh—Refresh selected elements on the page rather than the whole page.

Image Action as JavaScript function—Define a JavaScript function that calls an action method on the controller.

Image Action as timed event—Configure an action method to fire at a predefined time interval.

Image Action as JavaScript event—Bind a JavaScript event (such as onclick) to a controller action method.

Image Indicating action status—Reflect the status of an asynchronous action on the page.

Partial Page Refresh

Any action component can refresh part of a page using the reRender attribute. This attribute contains a comma-separated list of identifiers (the id values) of Visualforce view components to be refreshed when the action is completed. The identifiers must be of Visualforce components, not raw HTML elements. If no reRender value is provided or the identifiers are invalid, the entire page is refreshed. This is the default behavior of an action component.

Listings 7.1 and 7.2 are a Visualforce page and controller that demonstrate partial page refresh. A commandButton is defined to increment an integer value in the controller when clicked, via the increment method. The amount to be incremented is passed from the page to controller during the click, using the param component. The increment method returns a null PageReference to remain on the current Visualforce page rather than navigating to a new page. This is a requirement for partial page refreshes.

An outputPanel displays the current value of the integer. The reRender attribute is set on the commandButton to refresh only the outputPanel rather than the entire page.

Listing 7.1 Visualforce Page Using Partial Page Refresh


<apex:page controller="MyPageController7_1">
<apex:form>
<apex:commandButton action="{!increment}" value="Increment"
reRender="result">
<apex:param assignTo="{!amount}" value="2" />
</apex:commandButton>
<apex:outputPanel id="result">The value is: {!value}
</apex:outputPanel>
</apex:form>
</apex:page>


Listing 7.2 Visualforce Controller Using Partial Page Refresh


public class MyPageController7_1 {
public Integer value { get; private set; }
public Integer amount { get; set; }
public MyPageController7_1() {
value = 0;
}
public PageReference increment() {
value += amount;
return null;
}
}



Note

Not every Visualforce component supports being the target of a reRender attribute. If you discover a component that is not refreshing properly, enclose it in an outputPanel component, give the outputPanel a unique id value, and specify that id value in thereRender attribute.


Action as JavaScript Function

The action component actionFunction allows you to call an Apex method in the controller as a JavaScript function. This decouples the user interface representation of the action from the action itself. You’ve already experienced action components that require a user to click a link or button to trigger a controller action. With actionFunction, you can call an action from anywhere in your page, including custom JavaScript code.

To use the actionFunction component, minimally specify an action to invoke in the action attribute, a JavaScript function name in the name attribute, and enclose it in a form component. Optionally, you can define arguments on the function by nesting param components inside theactionFunction tag. You can also define a JavaScript function to be invoked when the action is complete by using the oncomplete attribute.

Listings 7.3 and 7.4 contain page and controller code demonstrating the use of actionFunction and partial page refresh. It multiplies a number by two using a controller method exposed as a JavaScript function. The resulting value is displayed on the page using a pageMessagescomponent and also refreshed in the call to the JavaScript function. This causes a stateful interaction in which the number is multiplied in a series.

Listing 7.3 Visualforce Page Using actionFunction


<apex:page controller="MyPageController7_3">
<apex:outputPanel id="result">
<apex:pageMessages />
<a onclick="timesTwoFunction('{!value}'); return false;">
Run
</a>
</apex:outputPanel>
<apex:form>
<apex:actionFunction name="timesTwoFunction"
action="{!timesTwo}" reRender="result">
<apex:param name="arg1" value="" assignTo="{!value}" />
</apex:actionFunction>
</apex:form>
</apex:page>


Listing 7.4 Visualforce Controller Using actionFunction


public class MyPageController7_3 {
public Integer value { get; set; }
public MyPageController7_3() {
value = 1;
}
public PageReference timesTwo() {
value *= 2;
addInfo('The result is: ' + value);
return null;
}
private void addInfo(String msg) {
ApexPages.addMessage(new ApexPages.Message(
ApexPages.Severity.INFO, msg));
}
}


Action as Timed Event

The actionPoller component invokes a method on the controller at a constant time interval. It can be used to perform a long-running operation incrementally, using a series of smaller steps. Another common usage is to perform a repetitive background task such as querying the database for some interesting business event. For example, a user interface designed for project staffers might use an actionPoller to automatically refresh a list of available resources once per minute.

To use actionPoller, provide a value for the action attribute, the controller method to invoke, and enclose it in a form component. This usage fires the action method every 60 seconds. Optionally, provide a value for the interval attribute, the time in seconds to wait between invocations of the action. This value must be 5 or greater. You can also set the onsubmit and oncomplete attributes, JavaScript functions to call before the action is invoked and after the action is completed.

Listing 7.5 is a sample page that uses the actionPoller along with the controller from Listing 7.4. Rather than requiring the user to click a link to multiply the number by two, the action happens automatically every 5 seconds.

Listing 7.5 Visualforce Page Using actionPoller


<apex:page controller="MyPageController7_3">
<apex:outputPanel id="result">
<apex:pageMessages />
</apex:outputPanel>
<apex:form>
<apex:actionPoller interval="5" action="{!timesTwo}"
reRender="result" />
</apex:form>
</apex:page>


Action as JavaScript Event

To invoke an action on the controller as a result of a JavaScript event, use the actionSupport component. This component fires an action whenever the event is detected on the enclosing Visualforce component.

The actionSupport component is placed within the body of a Visualforce component that fires the JavaScript event of interest. For example, an inputField component renders an HTML input element, so it fires standard JavaScript events such as onfocus, onblur, onclick, and so forth. Placing an actionSupport component within the inputField component allows it to listen for one of these events and invoke a controller method in response.

To use actionSupport, specify the name of the controller method to invoke in its action attribute, and a single JavaScript event to listen for in the event attribute. By default, actionSupport overrides the default browser-level handlers for the selected event. To disable this behavior, include a disableDefault attribute with the value of false. The onsubmit and oncomplete attributes are also supported to allow pre- or postprocessing of the request using your own JavaScript function.

Reusing the controller code from Listing 7.4, the Visualforce page in Listing 7.6 fires the timesTwo action when the text field receives focus. Try it by clicking somewhere else on the page, and then into the text field.

Listing 7.6 Visualforce Page Using actionSupport


<apex:page controller="MyPageController7_3">
<apex:outputPanel id="result">
<apex:pageMessages />
</apex:outputPanel>
<apex:form>
<apex:inputText>
<apex:actionSupport action="{!timesTwo}"
event="onfocus" reRender="result" />
</apex:inputText>
</apex:form>
</apex:page>


Indicating Action Status

You’ve learned how to invoke actions asynchronously. To notify users when asynchronous actions are being performed, use the actionStatus component in conjunction with any action component.

The actionStatus component can notify users of two states: when an asynchronous action is started and when it is stopped. To use it, place it in the location on your page where you want to show the status message. Use the startText and stopText attributes to specify the messages to be shown to the user. If you need to pass arguments to the action, use a nested param component.

Listing 7.7 provides an example of using the actionStatus component, building on the page from Listing 7.6 and the controller from Listing 7.4. When the text field receives focus, the action is fired, and the status message changes to Started. When the action is complete, the status message is set to Stopped.

Listing 7.7 Visualforce Page Using actionStatus


<apex:page controller="MyPageController7_3">
<apex:outputPanel id="result">
<apex:pageMessages />
</apex:outputPanel>
<apex:actionStatus id="status"
startText="Started" stopText="Stopped" />
<apex:form>
<apex:inputText>
<apex:actionSupport action="{!timesTwo}"
event="onfocus" reRender="result" status="status" />
</apex:inputText>
</apex:form>
</apex:page>


To display an image or a stylized message, you can use the start and stop facets. Facets are modifiers accepted by some Visualforce components to specify rich values that cannot be contained in XML attributes, such as nested HTML elements. Listing 7.8 is an example of using the facets to mark up the status message with H2 HTML heading elements.

Listing 7.8 Code Snippet Using actionStatus with Facets


<apex:actionStatus id="status">
<apex:facet name="stop">
<h2>Stopped</h2>
</apex:facet>
<apex:facet name="start">
<h2>Started</h2>
</apex:facet>
</apex:actionStatus>


To display a dynamic status message, you can write a JavaScript function to modify HTML elements on the page and call it from the actionStatus component. The actionStatus component supports the onStart and onStop attributes, which specify JavaScript functions to be invoked when the associated action is started and stopped. Listing 7.9 provides an example of this usage, using JavaScript to update the HTML content of an outputPanel in response to the actionStatus changing state.

Listing 7.9 Code Snippet Using actionStatus with JavaScript


<apex:page controller="MyPageController7_3">
<script type="text/javascript">
function start() {
document.getElementById("{!$Component.myStatus}").innerHTML = 'Started';
}
function stop() {
document.getElementById("{!$Component.myStatus}").innerHTML = 'Stopped';
}
</script>
<apex:outputPanel id="result">
<apex:pageMessages />
</apex:outputPanel>
<apex:actionStatus id="status"
onStart="start();" onStop="stop();" />
<apex:outputPanel id="myStatus"></apex:outputPanel>
<apex:form>
<apex:inputText>
<apex:actionSupport action="{!timesTwo}"
event="onfocus" reRender="result" status="status" />
</apex:inputText>
</apex:form>
</apex:page>


Referencing Visualforce Components from JavaScript

In Listing 7.9, the status of the action invocation is displayed in the element myStatus using JavaScript. For the purposes of the example, the element is an outputPanel Visualforce component rather than a simple div tag. This illustrates an important aspect of using JavaScript in Visualforce pages.

Each Visualforce component is assigned a unique identifier, set in its id attribute. When you override this id attribute and provide your own value, Visualforce fully qualifies it by affixing the identifiers of any containers included between your component and the root page component.

If your JavaScript code attempts to reference a Visualforce component using the raw identifier as it appears in the HTML, it will fail to locate it. Instead, use {!$Component.id}, where id is the identifier you set on your Visualforce component. When the page is rendered, Visualforce reads this token and replaces it with the fully qualified value of the identifier. If the identifier cannot be found, the token is replaced with an empty string.

If your component is contained within a form component, you must provide the form with an id value as well and include the form identifier in the component reference. For example, if the form identifier is myForm and the component you want to obtain a reference to is myText, the usage is {!$Component.myForm:myText}.


Tip

Use the View Source feature of your Web browser or a plug-in such as Firebug to debug component identifier problems.


Modular Visualforce

Visualforce pages that are modular, composed of a number of smaller, reusable building blocks, improve usability by providing consistent appearance and behavior. They are also easier to develop and maintain. Common functionality is defined once in a single place rather than repeated in multiple pages.

Visualforce provides several features you can use to create modular, highly maintainable pages:

Image Static resources—Reusable images, scripts, stylesheets, and other static content can be stored in static resources, available for embedding in all Visualforce pages in the Force.com organization.

Image Inclusion—The contents of one Visualforce page can be included in another page. A common use for this is page headers and footers.

Image Composition—Composition allows one Visualforce page to serve as a template for another. The template specifies the static and dynamic portions of a page. Use the template to inject dynamic content while maintaining a consistent page layout and structure.

Image Custom Visualforce components—Visualforce provides a library of standard components such as pageBlock and dataTable, but also allows you to define your own custom components, reusable in any page.

Static Resources

Static resources are containers for content used in Visualforce pages that does not change. Examples of unchanging content include images, stylesheets, and JavaScript files. Although any service that allows storage of URL-accessible data can perform a similar role, static resources have the benefit of being tightly integrated with the Visualforce page. Their names are validated when the page is compiled, preventing the creation of a page that refers to an invalid static resource. They are also inaccessible to anonymous public Internet users. Users not authenticated to your Salesforce organization cannot load your static resources unless you explicitly allow it using Force.com Sites.

A static resource can be a single file or a zip archive consisting of many files. The maximum size of a single static resource is 5MB, and no more than 250MB of static resources can be defined in any single Force.com organization.

To create a new static resource, follow these steps:

1. In the App Setup area, click Develop, Static Resources.

2. Click the New button to add a new static resource.

3. Enter a name for the static resource. The name cannot contain spaces or other nonalphanumeric characters, must begin with a letter, and must be unique. The name is used to refer to the static resource in Visualforce pages.

4. Specify an optional description to explain the purpose of this static resource to other users.

5. Click the Browse button to find a file in your file system to provide the content for the static resource.

6. Leave the Cache Control setting at its default value, Private. This setting is discussed later in the “Introduction to Force.com Sites” subsection.

7. Click the Save button to complete the static resource definition.

If your static resource contains a single file, refer to it in your Visualforce page using the syntax {!$Resource.name}, where name is the name of the static resource to include.

The syntax is different for referring to a single file within a static resource that is a zip archive. Use {!URLFOR($Resource.name, 'path/tofile')}, where name is the name of the static resource, and path/tofile is the full path to the desired file.

Inclusion

A simple way to create modular Visualforce pages is to use the include component. It embeds the content of the included page in the current page. The pageName attribute specifies the name of the Visualforce page to include. The included page must be a Visualforce page. You cannot include arbitrary URLs.

Listing 7.10 provides an example of using the include component. It embeds the page named SkillsMatrix between two horizontal rules.

Listing 7.10 Visualforce Page Using include


<apex:page>
<hr />
<apex:include pageName="SkillsMatrix" />
<hr />
</apex:page>


When a single Visualforce page ends up containing multiple controllers due to the include component, controllers are isolated from each other and operate independently. The controller of the included page does not have access to the state of the controller on the parent page, and vice versa. But pages are included inline, so JavaScript functions and DOM references can be made across included pages without security restrictions.


Caution

Be careful when using messages and pageMessages components in pages that are to be included in other pages. If the included page and parent page both supply one of these components, the same page messages will be rendered in multiple locations.


Composition

Composition is a powerful way to create modular Visualforce pages. It allows a Visualforce page to be defined as a template. The template can contain static content and placeholders for content that can be overridden by an implementing page. This enforces a standard structure for the pages without requiring Visualforce developers to remember a sequence of include components. It also places more control over the appearance of many pages within the scope of a single page (the template) for easier maintenance.

In the template page, the insert component is used to define a named area that can be overridden by a page implementing the template. The implementing page uses the composition component to set the name of the page to serve as its template. It then provides content for the named areas of the template using the define component.

For example, a template might consist of a header, body, and footer, with horizontal rules between each. Listing 7.11 defines this template page, named MyPage7_11. Note that the header area includes its own default content. This optional content is rendered in the event that content is not provided by an implementing page.

Listing 7.11 Visualforce Page as Template


<apex:page>
<apex:insert name="header">
<h1>Header</h1>
</apex:insert>
<hr /><apex:insert name="body" />
<hr /><apex:insert name="footer">
Inheriting the footer content
</apex:insert>
</apex:page>


The template is not interesting to render by itself, but in Listing 7.12 it’s implemented using the composition component. The template attribute specifies the template defined in Listing 7.11, which should be named MyPage7_11 for this example to work properly. The three dynamic areas are merged into the template to result in the final rendered output. The header area is provided, so it overrides the content defined by the template. The footer is inherited from the template.

Listing 7.12 Visualforce Page Using Template


<apex:page>
<apex:composition template="MyPage7_11">
<apex:define name="header">
Overriding the header content
</apex:define>
<apex:define name="body">
This is the body content
</apex:define>
</apex:composition>
</apex:page>


Composition works with multiple controllers identically to the include component. They run independently of each other, but all content is rendered in the same page.

Custom Visualforce Components

Custom components allow you to build a library of reusable user interface elements, encapsulating behavior and appearance while integrating with the data on the page and in the controller using the standard expression language. With custom components, all the functionality of standard components such as pageBlock and inputField is available to you to define from scratch using Visualforce and Apex code.

Custom components can be used to hide the implementation details of client-side technology like JavaScript. For example, a component can wrap a JavaScript user interface library such as Sencha’s Ext JS, freeing Visualforce page developers from the details of integrating Ext JS code into their pages. Custom components can also serve as full-blown pages themselves, reading and writing in the Force.com database through standard or custom controllers.

Defining a Custom Component

To create a new component, select File, New, Visualforce Component in the Force.com IDE. Or, using the Web browser, navigate to App Setup and click Develop, Components.

Custom components are defined with component as the root-level element rather than the familiar page. Following the component tag is an optional set of attribute components specifying the names and types of variables that can be shared between the page and the component. Supported types are primitives, standard and custom database objects, one-dimensional arrays, and custom Apex classes. Attributes can be declared as required, meaning that a page using the component must provide a value or it fails to compile. Attributes can also be assigned to member variables in a controller using the assignTo attribute.

The remainder of the component definition is identical to a standard Visualforce page, containing a combination of JavaScript, CSS, HTML elements, and standard components, as well as other custom components.

Listing 7.13 provides an example of a component for showing an address on a Google Map.

Listing 7.13 Custom Visualforce Component to Render Google Map


<apex:component >
<apex:attribute name="address" type="string" required="true"
description="Address to show on the Google map" />
<apex:includeScript
value="https://maps.googleapis.com/maps/api/js?sensor=false" />
<script>
var geocoder;
var map;
function init() {
geocoder = new google.maps.Geocoder();
var latlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
zoom: 17,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
}

function renderAddress(address) {
geocoder.geocode( { 'address': address },
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert("Geocode failed: " + status);
}
});
}
var previousOnload = window.onload;
window.onload = function() {
if (previousOnload) {
previousOnload();
}
init();
renderAddress('{!address}');
}
</script>
<div id="map-canvas" style="width: 320px; height: 480px;"></div>
</apex:component>


Using a Custom Component

Using a custom component in a page is much like using a standard component. The difference is that instead of prefacing the component with the apex namespace, you use c. Listing 7.14 shows an example of using the custom component defined in Listing 7.13 to render a Google Map for an address. It references the GoogleMap component, followed by a value for its required address attribute containing the street address to render on the map. In this example, the attribute value is hard-coded into the page, but this is not the only way to provide an attribute value. Like standard components, attribute values can include expression language, enabling them to share data with the controller.

Listing 7.14 Visualforce Page Using Custom Component


<apex:page>
<c:GoogleMap address="1 market st. san francisco, ca" />
</apex:page>


Dynamic Visualforce

Normally when a user visits a Visualforce page, Force.com constructs HTML or other content from the Visualforce components and their bindings to the controller. In contrast, dynamic Visualforce features allow the definition of the page itself, both its components and their bindings to the controller, to be determined at runtime, outside of the page. These features are most often used by software vendors who deliver Force.com applications on the Salesforce AppExchange, where the same application code must run within multiple, distinct customer organizations and adapt itself accordingly.

This section covers dynamic Visualforce features in more detail in the following subsections:

Image Dynamic field references—Dynamic field references allow the fields displayed in a Visualforce page to be injected into the page when viewed by a user. They can be provided by Apex code in the page controller or by Field Sets, a type of declarative metadata configurable without code.

Image Component generation—Visualforce pages can be constructed dynamically in Apex code. This can be essential for certain specialized user interfaces, but come with trade-offs not present with static pages.

Dynamic Field References

Dynamic field references are designed for situations in which you need to be flexible about which field to render. Ordinary field references are found in Visualforce components and determine their relationship to the controller. For example, an outputText component with content{!project.Name} renders the Name field of the object named project in the controller. The equivalent dynamic field reference is {!project[field]}, where field is a String value containing the name of the field to display.

The data referenced by a dynamic field reference must be available at runtime or an error will occur. If you’re using a standard controller, call the method addFields to notify the controller about new fields if possible, and it will take care of retrieving the data. For custom controllers, controller extensions, or queries involving related objects, build a dynamic SOQL query string and execute it with Database.query.

Listings 7.15 and 7.16 provide the Visualforce controller and page code for a simple example of dynamic field references. The Visualforce page renders a simple XML-encoded collection of Project records, embedded in HTML. The determination of which fields to display from each Project record is determined dynamically inside the controller. The fields are rendered in the page using two nested repeat components. The outer repeat iterates over an array of Project records returned by the controller. The inner repeat cycles through each field name from the controller, combining it with the record reference to obtain the value of that field for the current record.

Listing 7.15 Visualforce Controller Using Dynamic Field References


public class MyPageController7_16 {
public List<String> fields { get; set; }
public List<Project__c> records { get; set; }
public MyPageController7_16() {
fields = new String[] { 'Id', 'Name', 'CreatedDate' };
records = [ SELECT Name, CreatedDate FROM Project__c ];
}
}


Listing 7.16 Visualforce Page Using Dynamic Field References


<apex:page controller="MyPageController7_16">
<pre>
<projects>
<apex:repeat value="{!records}" var="record">
<project>
<apex:repeat value="{!fields}" var="field">
<{!field}>{!record[field]}</{!field}>
</apex:repeat>
</project>
</apex:repeat>
</projects>
</pre>
</apex:page>


Using Field Sets

Imagine the fields variable in Listing 7.15, which contains the list of field names to display on the Visualforce page, must be maintained by a nondeveloper. You could create a custom object to store the fields in the database and build a Visualforce user interface to manage them. Or you could use field sets and avoid all of that work.

A field set is a user-defined ordered list of fields on an object that can be referenced from Visualforce or Apex. A field set is editable using an administrative user interface built in to Force.com, leaving the code that uses it unchanged. For custom objects, go to the App Setup area; click Create, Objects; select the object; and find its Field Sets section. Standard objects are also in the App Setup area under Customize.

Once a field set is created, it can be referenced in a Visualforce component with the syntax {!$ObjectType.ObjectName.FieldSets.FieldSetName}, where ObjectName is the name of the standard or custom object that the field set is defined on, and FieldSetName is the name of the field set.

The fields of a field set are automatically loaded by the standard controller. For custom controllers, add accessors for the fields and dynamically construct SOQL from the field set to ensure the data is available to the page.

Component Generation

Dynamic field references are useful when you do not know what fields to display. Component generation comes into play when you do not know what object to render. It allows the construction of a Visualforce page from Apex code.

To start using component generation, add one or more dynamicComponent elements to your Visualforce page. This serves as the container into which the generated components are injected. The dynamicComponent is bound to a controller method, specified in the componentValueattribute, that must return an instance of Component.Apex.* to be rendered.

Listings 7.17 and 7.18 show a controller and page that leverage component generation to display a detail component bound to the user’s selection of one of three object types. A dynamic SOQL statement is generated using the list of accessible fields from the selected object type to retrieve the most recently modified record. The generated detail component is bound to its result.

Listing 7.17 Visualforce Controller Using Dynamic Components


public class MyPageController7_18 {
public SObject record { get; set; }
public String selectedObject { get; set; }
public List<SelectOption> getAvailableObjects() {
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption('Project__c', 'Project'));
options.add(new SelectOption('Timecard__c', 'Timecard'));
options.add(new SelectOption('Contact', 'Contact'));
return options;
}
public PageReference refresh() {
Schema.SObjectType targetType =
Schema.getGlobalDescribe().get(selectedObject);
Map<String, Schema.SobjectField> fields =
targetType.getDescribe().fields.getMap();
List<String> queryFields = new List<String>();
for (String s : fields.keySet()) {
if (fields.get(s).getDescribe().isAccessible()) {
queryFields.add(s);
}
}
String soql = 'SELECT ';
for (String s : queryFields) {
soql += s + ', ';
}
soql = soql.substring(0, soql.length() - 2);
soql += ' FROM ' + selectedObject;
soql += ' ORDER BY LastModifiedDate DESC LIMIT 1';
try {
record = Database.query(soql);
} catch (QueryException e) {}
return null;
}
public Component.Apex.Detail getComponent() {
Component.Apex.Detail result =
new Component.Apex.Detail();
result.expressions.subject = '{!record.Id}';
result.title = false;
result.relatedList = false;
return result;
}
}


Listing 7.18 Visualforce Page Using Dynamic Components


<apex:page controller="MyPageController7_18">
<apex:form >
<apex:selectList value="{!selectedObject}" size="1">
<apex:selectOptions value="{!availableObjects}"/>
</apex:selectList>
<apex:commandButton value="Refresh" action="{!refresh}" />
</apex:form>
<apex:dynamicComponent componentValue="{!component}"/>
</apex:page>



Note

Component generation is not a viable substitute for standard static Visualforce pages. Its use should be strictly limited to user interfaces that adapt to user actions in ways that can’t be coded in static markup.


Single-Page Applications in Force.com

A single-page application is an application that runs almost entirely within the Web browser. In contrast, older Web application architectures generate the appearance and behavior of Web pages primarily on the server. Single-page applications tend to be more interactive and responsive than Web applications that rely on full or even partial page refreshes from the server.

Single-page applications can be challenging to build as they are heavily reliant on client-side JavaScript code. Many JavaScript frameworks have sprouted up to assist developers. They address the difficulties in implementing complex user interfaces by separating the concerns of Web user interfaces using Model-View-View Model (MVVM) or Model-View-Controller (MVC) patterns. Some examples of frameworks to support single-page application development are Backbone.js, Knockout.js, AngularJS, and Ember.js.

At first glance, this seems to replace much of Visualforce. Although it does replace the Web-rendering portions of Visualforce with its own data binding and templating technologies, Visualforce continues to provide the glue that makes everything work smoothly. For example, it loads the single-page application code, making communication between the user’s Web browser and Force.com secure and authenticated without additional development effort. The resulting blend of Force.com and JavaScript performs better than Visualforce for many types of user interfaces, minimizes proprietary code, and keeps back-end dependencies clear and modular to maximize testability.

JavaScript Remoting

JavaScript remoting allows a controller method to be invoked directly from JavaScript with no Visualforce components necessary. Instead, you annotate the controller method with @RemoteAction and write a small amount of JavaScript to call it.

Although similar in function to JavaScript remoting, the actionFunction Visualforce component differs in some significant ways. The actionFunction component is designed for use in a Visualforce page with other native Visualforce components. Like most Visualforce components, it uses a form to create a stateful interaction between the controller and the page. This is not the case with remoting, which makes it a bit more responsive as a result. Remoting is also asynchronous, while the actionFunction component is synchronous.

JavaScript remoting is particularly helpful in the development of single-page applications on Force.com. With JavaScript remoting, the focus of the Force.com platform shifts to the back end. It serves the raw resources to power the user interface, both static files and dynamic data via controller method invocations. Once loaded, the user interface is rendered entirely in JavaScript within the browser, with callouts made to the Apex controller as needed for its data services.

Force.com with AngularJS

AngularJS is a popular open source Web development framework located at http://angularjs.org. It is a powerful tool for using the MVVM pattern, or Model-View-Whatever (MVW) as Google prefers it, in your Web application. For example, you can take advantage of its bidirectional data binding to tie the application’s model to its view, making Angular responsible for keeping them in lockstep at all times. This type of tight data binding provides users an experience free of Refresh and Save buttons and confusing mismatches between the model and view.

The demonstration page shown in Figure 7.1 is adapted from steps 0 through 5 of the Angular tutorial available at http://docs.angularjs.org/tutorial. It retrieves a list of projects from the Force.com database and allows the user to order them by name or date created, and search the list by name.

Image

Figure 7.1 Project list using Angular and JavaScript remoting

An implementation of the Visualforce controller and page code for the Angular-powered project list can be found in Listings 7.19 and 7.20. The subsections that follow provide a code walk-through of the Angular-specific aspects of Listing 7.20.

Listing 7.19 Visualforce Controller Using RemoteAction


public with sharing class MyPageController7_20 {
@RemoteAction
public static List<Project__c> load() {
return [SELECT Name, Location__c, CreatedDate
FROM Project__c ];
}
}


Listing 7.20 Visualforce Page Using Angular


<apex:page controller="MyPageController7_20">
<style>
.toolbar { margin-bottom: 20px; }
td { padding: 5px; }
</style>
<script>
function ProjectListCtrl($scope, $rootScope) {
MyPageController7_20.load(function(result, event) {
if (event.status) {
$scope.projects = result;
$rootScope.$apply();
}
}, { escape: false });
$scope.orderProp = 'CreatedDate';
}
</script>
<apex:pageBlock tabStyle="Project__c" title="Projects">
<apex:outputPanel html-ng-app=""
html-ng-controller="ProjectListCtrl">
<div class="toolbar">
Search: <input ng-model="query" />
Sort by:
<select ng-model="orderProp">
<option value="Name">Alphabetical</option>
<option value="CreatedDate">Newest</option>
</select>
</div>
<table>
<tr ng-repeat="project in projects
| filter:query | orderBy:orderProp">
<td>
<apex:outputText value="{{project.Name}}" />
</td>
<td>
<apex:outputText value="{{project.Location__c}}" />
</td>
<td>
<apex:outputText value="{{project.CreatedDate
| date}}" />
</td>
</tr>
</table>
</apex:outputPanel>
</apex:pageBlock>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js">
</script>
</apex:page>


Angular Controller

The Angular controller is responsible for the business logic of a single view. In Listing 7.20, the Angular controller is named ProjectListCtrl and specified in an in-line script tag. It invokes the remote action load on the Visualforce controller with the option escape: false. This instructs it to forgo HTML entity encoding of the remote action’s response. When the remote action is completed, the resulting array of projects is provided to Angular, and all its bound user interface elements are notified using the $apply() method.

Angular Template

Much like a Visualforce page, an Angular template brings the Angular controller and model together into a rendered Web page. It contains HTML, CSS, and Angular-specific markup.

Listing 7.20 contains a single Angular template within a Visualforce outputPanel component. Important aspects of the template are described in the following list:

Image The outputPanel contains custom HTML attributes (prefaced with html- to make them acceptable to Visualforce) to specify the Angular controller and ng-app to register the DOM with Angular. In Visualforce, this sort of control over the HTML output is only possible in anoutputPanel.

Image The two HTML input fields are bound to the controller using the ng-model attribute.

Image The table row is repeated for each element in the projects model, filtered by the input query and ordered by the drop-down selection.

Image Markup (in double curly brace notation) is used to output elements of the model within outputText components.

Image A standard HTML script tag includes version 1.0.7 of Angular from Google. This could just as well be loaded from a Force.com static resource or a Visualforce component with the script in-line.

Introduction to Force.com Sites

Sites is a feature of Force.com that enables public access to your Visualforce pages. A site is a collection of ordinary Visualforce pages and access control settings assigned to a unique base URL. You can define one or many sites within a Force.com organization. Sites can be individually brought up or down by your organization’s system administrator.

This section divides the discussion of Force.com Sites into four parts, summarized next:

1. Enabling and creating a site—Turn on the Force.com Sites feature and create your first site.

2. Security configuration—Configure the privileges granted to the anonymous user of your site.

3. Adding pages to a site—Select Visualforce pages that are accessible within a site.

4. Authenticating users—Blend public and private pages by integrating a site with Customer Portal.

Enabling and Creating a Site

To enable Force.com Sites for the first time in your organization, go to the App Setup area and click Develop, Sites. You should see the screen shown in Figure 7.2.

Image

Figure 7.2 Enabling the Force.com Sites feature

You must pick a Force.com domain name to continue. A domain name provides a unique, root address for all of your sites. You can remap this address to your own brand-name address (not Force.com) by configuring a CNAME alias on your domain hosting provider.

Enter your domain name, select the box to indicate that you’ve read the terms of use, and click the Check Availability button. After your domain name has been accepted, you can define your first site. Adding a site also creates a number of sample components, pages, and controllers in your organization.

To create a site, go to the App Setup area; click Develop, Sites; then click the New button. You should see a page like Figure 7.3. Provide a label and name for the site, such as www. The label is shown in the list of sites and clicking on it allows you to edit the site’s properties. Set the Active Site Home Page setting to UnderConstruction. This is a standard placeholder page provided with Force.com to let visitors know that the site is not available yet.

Image

Figure 7.3 Creating a new site

After your first site is defined, the main Sites page should look as shown in Figure 7.4.

Image

Figure 7.4 Sites main page

Security Configuration

When a new site is created, a corresponding profile is also created to manage the privileges of the guest user. The guest user is a special type of Salesforce.com license that represents the anonymous user of your site.

The guest profile for each site is configured using the native user interface. To view the profile, navigate to the Site Details page for the site and click the Public Access Settings button. Configure the privileges of the guest profile with extreme caution because mistakes can expose sensitive data in your Force.com organization to the entire world.


Note

The guest profile does not appear with other profiles in the Administration Setup area (Manage Users, Profiles). You must use the Public Access Settings button on the Sites Detail page to reach it.


If a page in a site uses static resources, make sure that they can be accessed from the guest profile. Go to each static resource and set its Cache Control to Public.

Adding Pages to a Site

A site starts off with a series of system-defined pages such as Exception and FileNotFound. These pages are shown to users in the event of errors in the site. You can redefine them by simply editing them.

You can also add your own custom pages to the site. To add pages, click the Edit button in the Site Visualforce Pages section. Select one or more pages from the list on the left and click the Add button to move them to the list of Enabled Visualforce Pages. Click Save when you’re done.

The URL of your pages is the default Web address of the site followed by the name of the page. For example, in Figure 7.5, the default Web address is https://force-book-3e-developer-edition.na15.force.com. If a page named MyPage is added to the site, users can access it at https://force-book-3e-developer-edition.na15.force.com/MyPage.

Image

Figure 7.5 Site Details page


Note

A site must be activated before any pages in it are accessible. To activate a site, select its Active check box in the Site Details page or click the Activate link on the main Sites page.


Authenticating Users

Anonymous users can be converted to named, authenticated users through the Customer Portal, or portal for short. A portal allows you to extend Force.com to your partners and customers without requiring full user accounts for each of them. It is tightly integrated with Force.com Sites.

Enable portal integration by clicking the Login Settings button on the Site Details page. In the Login Settings section, click the Edit button and select an existing portal from the drop-down list, and then click the Save button. Figure 7.6 shows a site enabled to log in to the portal named Customer Portal.

Image

Figure 7.6 Login Settings page


Note

If no portals are listed, you must configure one that is login enabled. Go to the App Setup area and click Customize, Customer Portal, Settings. Setting up a portal is not within the scope of this book, so refer to the online documentation for more information.


Sample Application: Enhanced Skills Matrix

This section builds on the Services Manager’s Skills Matrix feature developed in Chapter 6, “User Interfaces.” Users of the Skills Matrix feature have requested the ability to compare a consultant’s skills with those of other consultants without navigating to a new page. They would like to see the ratings of other consultants in the same skill visually layered atop the existing Skills Matrix user interface, as shown in Figure 7.7.

Image

Figure 7.7 Skills Matrix with comparison overlay

The following technologies from this chapter are used in the development of the feature:

Image JavaScript integration—jQuery UI (a free, open source JavaScript and CSS library for Web applications) is integrated to provide an easing effect, fading in and out the list of other resources and their skill ratings. jQuery UI is available at http://jqueryui.com.

Image Custom Visualforce components—The overlay containing the other consultants’ skills is encapsulated in its own custom Visualforce component and controller.

Image actionSupport component—This component is used to show and hide the skills comparison overlay when the user hovers over an informational icon.

Begin by developing a custom component for retrieving and rendering a list of skill ratings and consultants. The input to this component is a skill type and a resource identifier of the currently selected consultant. The skill type is the name of a proficiency that consultants are measured on, a picklist value from Skill__c.Type__c, such as Java or Apex. The resource identifier is used to exclude the current consultant from the list because his or her skill ratings are already shown on the Skills Matrix user interface.

Listing 7.21 provides a sample implementation of the controller to support the requirements, and Listing 7.22 shows the custom component that uses it.

Listing 7.21 CompareSkillsController


public class CompareSkillsController {
public String contact { get; set; }
public String skill { get; set; }
public List<Skill__c> getData() {
return [ SELECT Contact__r.Name, Type__c, Rating__c
FROM Skill__c
WHERE Type__c = :skill
AND Rating__c NOT IN ('', '0 - None') AND
Contact__c != :contact
ORDER BY Rating__c DESC ];
}
}


Listing 7.22 CompareSkillsComponent


<apex:component controller="CompareSkillsController">
<apex:attribute name="skillType" description="Type of skill"
type="String" required="true" assignTo="{!skill}" />
<apex:attribute name="contactId"
description="Id of contact to compare with"
type="String" required="true" assignTo="{!contact}" />
<apex:pageBlock >
<apex:pageBlockSection collapsible="false" columns="1">
<apex:facet name="header">
Other Resources with {!skillType}
<span style="padding-left: 30px;">
<a onclick="hideOverlay(); return false;"
href="" style="text-decoration: underline;">Hide</a>
</span>
</apex:facet>
<apex:pageBlockTable value="{!data}" var="item">
<apex:column value="{!item.Contact__r.Name}" />
<apex:column value="{!item.Rating__c}" />
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:component>


To incorporate this component into the Skills Matrix page, perform the following steps:

1. Add the code shown in Listing 7.23 to the bottom of the SkillsMatrixController class. The new method and property are used to refresh the skills comparison component.

Listing 7.23 Adding Component Support to the Skills Matrix Controller


public PageReference refreshCompareSkills() {
return null;
}
public String selectedSkillType { get; set; }


2. Edit the Skills Matrix page to add sidebar="false" to the apex:page component. This frees up extra horizontal screen real estate that is used to display the skills comparison overlay. Also add the CSS in Listing 7.24 to the style tag.

Listing 7.24 Adding Component CSS to the Skills Matrix Page


.compare-skills {
position: absolute;
width: 400px; height: 250px;
display: none;
}


3. Also on the Skills Matrix page, insert the code in Listing 7.25 after the closing tag of the form component. It adds an outputPanel containing the CompareSkillsComponent, rendered as an overlay with a fading effect from jQuery UI in the showOverlay JavaScript function.

Listing 7.25 Adding CompareSkillsComponent to the Skills Matrix Page


<apex:outputPanel id="compareSkills" styleClass="compare-skills">
<c:CompareSkillsComponent skillType="{!selectedSkillType}"
contactId="{!selectedContactId}" />
</apex:outputPanel>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
<script>
function showOverlay(e) {
$('.compare-skills').css('top', e.layerY)
.css('left', e.layerX).fadeIn();
}
function hideOverlay() {
$('.compare-skills').fadeOut();
}
</script>


4. For the final step, insert the code given in Listing 7.26 to the Skills Matrix page, immediately following the opening tag of the column component containing the skill rating (headerValue="Rating"). It adds an informational icon beside each skill. Hovering over this icon displays the overlay containing the skills comparison.

Listing 7.26 Adding actionSupport to the Skills Matrix Page


<apex:image value="/img/msg_icons/info16.png"
style="margin-top: 2px; margin-right: 10px;">
<apex:actionSupport event="onmouseover"
action="{!refreshCompareSkills}" rerender="compareSkills"
oncomplete="showOverlay(event);" onsubmit="hideOverlay();">
<apex:param name="p1" value="{!skill.Type__c}"
assignTo="{!selectedSkillType}" />
</apex:actionSupport>
</apex:image>


Summary

In this chapter, you’ve seen some of the ways Visualforce can produce effective user interfaces, from action components that provide Ajax behavior to the integration of open source Web application technologies such as JQuery. Before switching gears in the next chapter, take a moment to review these key points:

Image Stick with standard and custom Visualforce components wherever possible to keep your user interface running smoothly with the rest of Force.com today and in future releases.

Image Strive to adopt the many features of Visualforce that foster modularity, such as composition and custom components, rather than copying and pasting code from page to page.

Image You can use Visualforce to create public-facing Web pages through Force.com Sites. Sites are simply a series of configuration settings that enable a guest profile to access a set of pages, extending your existing investment in Visualforce.