Visualforce

Javascript and Visualforce: Tips and Tricks

by Patrick Connelly posted on January 09, 2017

In the web 7.0 or whatever version of the web we’re in, Javascript is king. Now, there’s lots of stuff you can do directly with Visualforce (like dynamic picklists) but sometimes for the best user experience you’ll want to use Javascript to make it even better. There are lots of Javascript tutorials out there and there are lots of Visualforce tutorials out there (don’t forget Trailhead) so I’m going to talk about some tricks that people should know when working with Javascript on Visualforce


Namespaced Component in Managed Packages

by Patrick Connelly posted on September 13, 2016

As part of my managed package crusade I decided I should delve into the world of Visualforce from a managed package. While pure Visualforce is going to be in my package that’s not nearly as interesting as packaging and using namespaced components as part of the package. So let’s take a look at how we can use a namespaced component.

Namespaced Component

The component that I created in my packaging org is simple. The Visualforce page provides an account Id and the component lists out each of the account’s cases. This component isn’t going to win any awards for originality, but it will serve it’s purpose.


Watermarking PDFs in Visualforce

by Patrick Connelly posted on May 09, 2016

Keeping on the PDF and Trailhead theme, lets take a look at adding watermarks to our PDFs. There was recently a developer boards post about watermarking a PDF and it dovetailed nicely into the previous posts.


apex:gaugeSeries and display report data

by Patrick Connelly posted on January 25, 2016

I recently helped out on a Developer Boards post about recreating a dashboard in Visualforce to create a home page component. This works great with analytics:reportChart assuming you are not using a gauge chart. However if you want to use a gauge chart then you’ll have to dive into the apex:gaugeSeries component and personally I found the documentation a bit lacking. So, let’s dive into how to create a gauge chart based on a summary report.


Salesforce1 Actions with Visualforce

by Patrick Connelly posted on January 03, 2016

Salesforce1 Actions can be very powerful. Most of the examples I have seen regarding Salesforce1 Actions have been around Global Actions that show up on the home page. I recently had the chance to play around with object specific actions and found that combined with Visualforce pages they can be very powerful.

Goal

The goal of this post is to create two quick actions for the Lead object. One that will reject a lead and one that will accept a lead.

Salesforce1 Goal

We will be doing this via a Visualforce page that has an onload action. This will be useful so that we can re-use this both for a standard page layout button as well as for our Salesforce1 Action


Dynamic dependent picklists in Salesforce

by Patrick Connelly posted on July 09, 2012

One thing that comes up a lot in the in the #salesforce IRC channel is doing dynamic Visual Force driven off of picklists. So, let’s buckle up and get to it.

Data Model

In this simple example we are going to make an extension to the case page. On this page we are going to us a custom Product/Version object to display on the page. The product list well be determined on the start/end date of the product. And the version will be driven by the currently selected product. Product

  • Name – The name of the product
  • Currently_Supported__c – Formula based on StartDate__c and EndDate__c (Integer version of a boolean)
  • StartDate__c – The date the product should be shown (Rollup min from the version)
  • EndDate__c – The date the product should be hidden (Rollup max from the version)

Version

  • Name – The name of the version
  • Currently_Supported__c – Formula based on StartDate__c and EndDate__c (Integer version of a boolean)
  • StartDate__c – The date the version should be shown
  • EndDate__c – The date the version should be hidden
  • Product__c – The product the version is related to

Apex Controller

public with sharing class ProductUtils {
    static public List<Product__c> getAllProducts(Boolean includeEOL) {
        //This is done since the formula field cannot return a boolean
        Integer currentlySupported = (includeEOL) ? 0 : 1;

        return [
            select Name
            from Product__c
            where Currently_Supported__c >= :currentlySupported
            order by Name
        ];
    }

    public static List<Product__c> getAllProducts() {
        return getAllProducts(false);
    }

    public static List<Version__c> getAllVersions(Id productId, Boolean includeEOL) {
        Integer currentlySupported = (includeEOL) ? 0 : 1;

        return [
            select Name,
                Product__c
            from Version__c
            where Currently_Supported__c >= :currentlySupported and
                Product__c = :productId
            order by Name
        ];
    }

    public static List<Version__c> getAllVersions(Id productId) {
        return getAllVersions(productId, false);
    }
}

These methods are simple util methods to get product information and version information

global with sharing class CaseEdit_ControllerExtension {
    private final Id recordId;
    private final Case record;
    private final ApexPages.StandardController controller;

    public Case_ControllerExtension(ApexPages.StandardController stdController) {
        this.controller = stdController;
        this.recordId = this.controller.getId();
        this.record = [
            select Product__c,
                Subject,
                Version__c
            from Case
            where Id = :this.recordId
            limit 1
        ];
    }

    public List<SelectOption> getProductList() {
        List<SelectOption> products = new List<SelectOption>();
        products.add(new SelectOption('', '--None--'));

        for (Product__c p: ProductUtils.getAllProducts()) {
            products.add(new SelectOption(p.Id, p.Name));
        }

        return products;
    }

    public Id getProduct() {
        return this.record.Product__c;
    }

    public void setProduct(Id productId) {
        this.record.Product__c = productId;
    }

    public List<SelectOption> getVersionList() {
        List<SelectOption> versions = new List<SelectOption>();
        versions.add(new SelectOption('', '--None--'));

        if (record.Product__c != null) {
            for (Version__c v: ProductUtils.getAllVersions(getProduct())) {
                versions.add(new SelectOption(v.Id, v.Name));
            }
        }

        return versions;
    }

    public Id getVersion() {
        return this.record.Version__c;
    }

    public void setVersion(Id versionId) {
        this.record.Version__c = versionId;
    }

    public PageReference doSave() {
        Case c = (Case) controller.getRecord();
        c.Product__c = this.record.Product__c;
        c.Version__c = this.record.Version__c;

        upsert c;

        return new PageReference('/'+c.Id);
    }
}

The controller has the getters and setters for the product and version. But most importantly the getters for productList and versionList. The versionList is triggered off the record’s product. The other part of this is that for whatever reason (I couldn’t find a good one) is the getRecord does not include the changes made to the Product__c and Version__c field, so you’ll need to set them by hand in the doSave method.

One thing to note is since this is all done in the controller extension and since get and set use the Id, the select list will have the correct thing set when editing an existing record.

Visual Force Page

<apex:page standardController="Case" extensions="CaseEdit_ControllerExtension" title="Case Edit" tabStyle="Case">
    <apex:form id="form">
        <apex:pageBlock title="Case Edit">
            <apex:pageBlockButtons>
                <apex:commandButton action="{!doSave}" value="Save" />
                <apex:commandButton action="{!cancel}" value="Cancel" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="Case Information">
                <apex:inputField value="{!Case.Summary}" required="true" />
                <apex:pageBlockSectionItem>
                    <apex:outputLabel for="productList" value="{!$ObjectType.Case.fields.Product__c.label}" />
                    <apex:actionRegion>
                        <apex:selectList value="{!product}" title="Product" size="1" id="products">
                            <apex:selectOptions value="{!productList}" />
                            <apex:actionSupport event="onchange" rerender="versions" />
                        </apex:selectList>
                    </apex:actionRegion>
                </apex:pageBlockSectionItem>
                <apex:pageBlockSectionItem>
                    <apex:outputLabel for="versions" value="{!$ObjectType.Case.fields.Version__c.label}" />
                    <apex:actionRegion>
                        <apex:selectList value="{!version}" title="Version" size="1" id="versions">
                            <apex:selectOptions value="{!versionList}" />
                        </apex:selectList>
                    </apex:actionRegion>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

The key parts of this is that the actionRegion surrounds both the item changing (product) and the dependent item (version). If you had a third picklist you wanted to trigger on you could add another actionSupport item and tell it to rerender that third list.

Conclusion

Dependent picklists are not very hard to do as long as you remember the actionRegion around both the source and target, and making sure to get the data from the picklist prior to upserting your record.