Salesforce Flows, Visualforce and Record Context

I was asked to find a solution for our field reps that would simplify the process of adding a completed task to their activities when they visited one of our retail stores.

We keep our retail locations in Salesforce.com as contacts under a master account, which is shared with all users using a special account sharing rule.

The solution I came up with was a simple flow that limited users to a specific set of enterable information, pre-filling the date of the activity, and marking the task complete when the activity was committed. Literally, the only thing they needed to do was select a picklist value and enter a comment about their visit. It was exactly what we were looking for.

The thing I didn’t like about the flow was that when a user entered it, context kind of got lost — meaning they started out from a contact record, but didn’t have a good visual cue about where they were once they got into the flow.

Sure, the flow was simple, but to me it’s still poor UX not to know the context of your work at all times. So, I decided to use a Visualforce page to solve the problem:

<apex:page standardController="Contact">
    <apex:sectionheader title="Add Retail Store Visit" subtitle="{!Contact.Name}"></apex:sectionheader>
    <flow:interview name="Retail_Store_Visit">
        <apex:param name="vContact" value="{!Contact.Id}"></apex:param>
        <apex:param name="vAccount" value="{!Contact.Account.Id}"></apex:param>
    </flow:interview>
</apex:page>

The trouble with this was that after the flow data was committed, the user would be returned to the beginning of the flow. That’s definitely not what I wanted. I needed to go back to the contact record I started from.

So I added the finishLocation attribute to the <flow:interview /> component tag. It would make sense that if I passed the Contact Id, the flow should return to the Contact record:

<flow:interview name="Retail_Store_Visit" finishLocation="{!URLFOR('/' + Contact.Id)}">
    <apex:param name="vContact" value="{!Contact.Id}"></apex:param>
    <apex:param name="vAccount" value="{!Contact.Account.Id}"></apex:param>
</flow:interview>

Nope. That didn’t do it. When the flow is entered, context gets lost, so Salesforce doesn’t really know where the user is anymore. Even using the vContact Apex parameter didn’t work.

I searched help documentation for an answer, but it wasn’t all that helpful. I searched Communities and came up empty. Then I searched the Salesforce Stack Exchange, where the only solution I could find was really convoluted, and didn’t even come close to solving my problem. I was vexed.

Taking a break to get a cup of coffee, a solution dawned on me that turned out to be pretty darned simple. All I needed was an Apex variable in the page, which I could pass to the finishLocation component tag once the flow was complete. Oddly enough, this method is not documented — at least not that I could find.

So…the final Visualforce page:

<apex:page standardController="Contact">
    <apex:variable var="theContact" value="{!Contact.Id}"></apex:variable>
    <apex:sectionheader title="Add Retail Store Visit" subtitle="{!Contact.Name}"></apex:sectionheader>
    <flow:interview name="Retail_Store_Visit" finishLocation="{!URLFOR('/' & theContact)}">
        <apex:param name="vContact" value="{!Contact.Id}"></apex:param>
        <apex:param name="vAccount" value="{!Contact.Account.Id}"></apex:param>
    </flow:interview>
</apex:page>

Using the Apex variable, users where returned to the contact record they started from, and could see the task they just added in the activity history related list. This was exactly what I was looking for. Everyone was happy.

If you need to return to a starting point when using flows and Visualforce pages, consider giving this solution a try.

,


Making a Field Appear Required on a Visualforce Page

I’ve been working on a force.com app with the requirement that a user must enter a valid email address on a Visualforce page before being able to save a record.

But they must also be able to insert the related contact’s email address by clicking a button instead of having to leave the edit page to go find it. That seemed simple enough, but it wasn’t. This is my solution for making a field appear required on a Visualforce page.

In my original Visualforce page, it seemed logical that if I set the recipient email field as required, all would work as expected. However, defining the field as required prevented my custom action in my page controller from firing and entering the email address.

Original Page Controller

public class GiftCardTestController {
    private ApexPages.StandardController std;
    public String cEmail {get;set;}
    public Gift_Card_Order__c gc {get;set;}
    public GiftCardTestController(ApexPages.StandardController stdCtrl) {
        std = stdCtrl;
    }

    //selects the email address of the related contact
    //and inserts into recipient email field.
    public void fillEmail() {
        gc = (Gift_Card_Order__c)std.getRecord();
        cEmail = [select Id, Email from Contact where Id = :gc.Contact__c].Email;
        gc.Recipient_Email__c = cEmail;
    }
}

Original Visualforce Page

<apex:page standardController="Gift_Card_Order__c" extensions="GiftCardTestController" title="Gift Card Test">
    <apex:form>
        <apex:pageblock title="Gift Card" mode="edit">
            <apex:pageblockbuttons location="top">
                <apex:commandbutton action="{!save}" value="Save"></apex:commandbutton>
                <apex:commandbutton action="{!cancel}" value="Cancel"></apex:commandbutton>
                <apex:commandbutton action="{!fillEmail}" value="Fill Email"></apex:commandbutton>
            </apex:pageblockbuttons>
            <apex:pageblocksection title="Email Info" columns="1">
                <apex:inputfield value="{!Gift_Card_Order__c.Contact__c}"></apex:inputfield>
                <apex:inputfield value="{!Gift_Card_Order__c.Recipient_Email__c}" required="true"></apex:inputfield>
            </apex:pageblocksection>
        </apex:pageblock>
    </apex:form>
</apex:page>

In this example, the fillEmail() action should select the related contact email address, and put the value in the Recipient_Email__c field so the user can see it.

But it’s not that simple it seems. When the field had the required="true" attribute set, the action would not fire because all validation is done on the client side and the page never posts back to the server — so the controller action never gets called.

So after some digging and asking for help on the Salesforce discussion boards, the solution was to make the Recipient_Email__c appear as if it’s required on the page (though it’s really not), and add a new save method to my controller to handle field validation on the server side when the record gets saved.

New Page Controller

public class GiftCardTestController {
    private ApexPages.StandardController std;
    public String cEmail {get;set;}
    public Gift_Card_Order__c gc {get;set;}
    public GiftCardTestController(ApexPages.StandardController stdCtrl) {
        std = stdCtrl;
    }

    public void fillEmail() {
        gc = (Gift_Card_Order__c)std.getRecord();
        cEmail = [select Id, Email from Contact where Id = :gc.Contact__c].Email;
        gc.Recipient_Email__c = cEmail;
    }

    // add custom save method...
    public pageReference save() {
        gc = (Gift_Card_Order__c)std.getRecord();

        // if the recipient email is null, add an error to the field
        // and return null to remain on the current page...
        if(gc.Recipient_Email__c == null) {
            gc.Recipient_Email__c.addError('A valid email address is required.');
            return null;
        }

        // otherwise, the field is filled, so it's okay to redirect to view page.
        // standard field validation will check for valid email format.
        else {
            return std.save();
        }
    }
}

New Visualforce Page

<apex:page standardController="Gift_Card_Order__c" extensions="GiftCardTestController" title="Gift Card Test">
    <apex:form>
        <apex:pageblock title="Gift Card" mode="edit">
            <apex:pageblockbuttons location="top">
                <apex:commandbutton action="{!save}" value="Save"></apex:commandbutton>
                <apex:commandbutton action="{!cancel}" value="Cancel"></apex:commandbutton>
                <apex:commandbutton action="{!fillEmail}" value="Fill Email"></apex:commandbutton>
            </apex:pageblockbuttons>
            <apex:pageblocksection title="Email Information" columns="1">
                <apex:inputfield value="{!Gift_Card_Order__c.Contact__c}"></apex:inputfield>

                <!-- Updated pageBlockSectionItem -->
                <apex:pageblocksectionitem>
                    <apex:outputlabel>Email Recipient</apex:outputlabel>
                    <apex:outputpanel layout="block" styleClass="requiredInput">
                        <apex:outputpanel layout="block" styleClass="requiredBlock"></apex:outputpanel>
                        <apex:inputfield value="{!Gift_Card_Order__c.Recipient_Email__c}"></apex:inputfield>
                    </apex:outputpanel>
                </apex:pageblocksectionitem>
                <!--// end pageBlockSectionItem -->

            </apex:pageblocksection>
        </apex:pageblock>
    </apex:form>
</apex:page>

Notice the <apex:pageblocksectionitem /> code to replace the original field. This is how we make the field appear with the “required” bar. A nifty trick that took some digging to discover. Hopefully this post saves someone else the time it took me to figure it out — and me the time when I forget it.

For convenience, here’s a Github Gist with field label & inline help that shows exactly how to make a field appear required on a Visualforce page.

,


AppleScript to Quickly Add Files in the macOS Finder

Today I had the need to add a bunch of named text files to a folder in the Finder on my Mac.

I found it a major pain to open BBEdit, make a new document, save it to where I wanted it, and then manually copy & rename the file back in the Finder. A lot of effort just to get 7 or 8 empty files with different names.

So, I threw together this little AppleScript to add empty files instead. The gist is once launched in the Finder (using FastScripts by Red Sweater naturally. Keystroke: cmd+option+shift+N), a dialog pops up that lets you enter a file title. Then the Finder creates that file in the front-most window. If no window is open, the file is added to your Desktop.

I found this to be more than twice as fast as the “traditional” method of making several files. Hopefully, it can help you out too. Remember, use it with FastScripts for quick keystroke access. Save as a script in the “Finder” scripts folder ("~/Library/Scripts/Applications/Finder/").

Here’s the code. Just copy and paste into AppleScript Editor and save…

property defaultFileName : "newFile.txt"
tell me to activate
set theFileName to text returned of (display dialog "Enter a file name:" default answer defaultFileName)
tell application "Finder"
    activate
    if the (count of windows) is not 0 then
        set theFolder to (folder of the front window) as text
        set theFolder to POSIX path of theFolder
    else
        set theFolder to POSIX path of (get path to desktop)
    end if
    set addedFile to (theFolder & theFileName)
    do shell script "touch '" & addedFile & "'"
    if the (count of windows) is not 0 then
        set addedFile to (POSIX file addedFile) as alias
        select addedFile
    end if
end tell

,