Wednesday, November 23, 2016

The curious case of the custom redirection on Salesforce Console



Every developer worth their salt knows that the easiest way of redirection from a page to another is by using everyone's favorite function

  public PageReference redirect() {
       PageReference pageRef = page.peskyProblemRedirection; 
       pageRef.setRedirect(true); 
       return pageRef; 
    }

And the method is called by adding it to the Action attribute of the CommandButton or link, which works like charm and the user is redirected to the page after completion of the action.
So why am I going back to the basics? Because this way of redirection causes a pesky little problem in using the Service Cloud or Sales Cloud console.

Let's illustrate the problem, let's say you have a visualforce page as follows:

<apex:page sidebar="false" showHeader="false" controller="myExampleController">
<apex:form >
<apex:pageBlock >    
  
         <apex:pageBlockButtons >
             <apex:commandButton action="{!Redirect}" value="Next Page"/>
          </apex:pageBlockButtons>
     
  </apex:pageBlock>
  </apex:form>
</apex:page>

The controller to this class is as follows:

public with sharing class myExampleController {
  public PageReference redirect() {
       PageReference pageRef = page.peskyProblemRedirection; 
       pageRef.setRedirect(true); 
       return pageRef; 
    }
}

This does what it says, you click a button and it takes you to the next page seamlessly.

The Problem

But now let's see when this page is added to the Salesforce Console.
Let's run the same code inside the console.

1. This is our first page
2. If we take a peek under the hood, we open the link of the tab inside the console and it shows our first page. PeskyProblemPage


3. Do the thing, click on next page and voila, we are redirected to the next page- as expected.

4. But here is where the problem starts- if we take a peek under the hood of the second page, we see things are not as they seem. If we click on the link of our second page as shown in annotation number 2 in the figure below, we notice that the link has not changed as shown in annotation number 3


Why is this a problem? That is because Salesforce does not auto refresh its pages every time and let's say the user refreshes the second page- it reopens the first one because the link still points to the first page. So what works here? The console toolkit, that can be referenced here, tells us that most of the console can be accessed navigated by using a Javascript library.


Solution

One solution for this issue is the use of Native OpenPrimaryTab method of the Console toolkit API. So we rewrite the page again using the Console Toolkit API, this time, however, we will set the redirection on the page itself.

So our new Page becomes as follows:

<apex:page>
    <apex:includeScript value="/support/console/28.0/integration.js" />
    <script type="text/javascript">
        //Get the enclosing primary tab, if you want to open a new tab, ignore this method
        var openPrimaryTab = function openPrimaryTab() {
            sforce.console.getEnclosingPrimaryTabId(callOpentab);
        }

        //Whatever the result, open it in the same tab
        var callOpentab = function callOpenSubtab(result) {
            sforce.console.openPrimaryTab(result.id,
                '/apex/peskyProblemRedirection', true, 'Page two');
        };

    </script>

    <apex:form>
        <apex:pageBlock>
            <apex:sectionHeader title="Page one" />
            <apex:pageBlockButtons>
                <apex:commandButton onclick="openPrimaryTab()" value="Next Page" />
            </apex:pageBlockButtons>
        </apex:pageBlock>
    </apex:form>

</apex:page>

As you can see, the magic happens using the onclick function that sets the page redirection on a console. If there is an action to perform before redirection, the same function can be used in oncomplete attribute of the button.

Taking this further,

This example above gives us the basic idea of how the redirection works on the console. Let's say you need to generate a dynamic page URL based on the data manipulation in the action method. E.g., send accountID to the new page from the tab. This can be achieved by using javascript remoting and calling the apex method in javascript. Take a look at the UNTESTED code below, that can get you started on exploration:


<script type="text/javascript">
    function getRemoteAccount() {
        Visualforce.remoting.Manager.invokeAction(
            '{!$RemoteAction.AccountRemoter.getAccount}',
            accountName,
            function(result, event) {
                if (event.status) {
                    sforce.console.openPrimaryTab(null,
                        '/apex/peskyProblemRedirection?id=' + result.id,
                        true, 'Page two');

                 }
            }, {
                escape: true
            }
        );
    }

 </script>

The possibilities are only limited by your imagination. Working with the Console in the past couple of years has given a greater sense of many things Salesforce developers usually take for granted. But once you get hang of it, Console is the best product ever made by Salesforce (Yes better than Lightning too!!!)

Have you encountered this problem before? Do you have any other solution? Share your experience in the comments below
Share:

Friday, November 4, 2016

Four secrets to improve the usability of your visualforce/Lightning pages on Salesforce

In the immortal words of a certain machine returning back in time, I am back. For now. After procrastinating for over a year and drafting a lot of rants- I am back with a very important coding lesson for you. For now.

When we are designing a Visualforce page or an app or a lightning component (added that only to trick google) or any web page for that matter, we often tend to wrap up things quickly. Ask anyone on the team, how to design a good User Experience? and the person will immediately throw buzz words like Bootstrap, angular and other useless libraries (did someone squint?)

Ok, Bootstrap, Angular-Js, and all the libraries are really cool and are useful in designing a fabulous UI. They are helpful in creating responsive pages that will work on all the devices but this post is not about those. Nope. For the purpose of this post, all the external libraries and buzzwords you use to decorate your resume are useless. (Adding Angular JS in your resume for a Salesforce consultant position when you don't know workflows is useless too, just saying). Another comment I receive fairly regularly is that- there are a lot many things you cannot do on salesforce. Which is true but still annoying. While there are a lot many things you cannot do, there are still a lot of things you can still do. One of those things is stop being annoying. Moving on.

Salesforce is a customer-centric system, as such, a user is at the center of whatever you do. Whenever you design an interface on Salesforce you have to remember that- someone will be paid to use the thing for 8 hours a day. If you design bad user experience, their job will be harder and reduce productivity and usability. And one important trick to remember designing a form is- DO NOT LET USER SCROLL. Make sure your form elements are reachable by tabbing.



So with that out of the way, let us take a look at the four secrets you should know before designing a visualforce page

1. Separate your data from the background
This is a tip that was given to me by the director of a college play. You clearly mark the area on the stage where you want the audience to focus their attention.
By default, any web system uses white background and text in black. This form is consistent unless you are on the Dark side or environment-friendly when you will use black background over white text. But don't be google when it comes to displaying complex data on the page. All you need to do is clearly separate the data from the background, you can do that by adding a thin gray background to your text or, as Salesforce does it, place the data between neat equidistant lines. If you are not using sidebar and headers, do include SectionHeader on the page. Make sure you set your data in a way, it is clearly distinguishable from the background.


2. Give visual feedback whenever you are processing information
This is visualforce building 101, if you are using a tag from the family of Command and Action (e.g., apex:commandButton, apex:commandLink, apex:actionfunction, apex:actionsupport etc) you HAVE TO use the apex:actionStatus. Don't leave your user guessing if the button press worked or no. There has to be a visual feedback.
You could be extra quirky to indicate what is happening or give an error message. Shiva has a good code for the same, you can use his action status in your code.

3. Take an extra hour to fix the error messages. Keep them consistent. 
Salesforce provides different ways to display error messages. Some are field level error messages, others are page level error. When developing a custom page, spend an extra effort to make sure your error messages are consistent. If you have a server-side validation, make sure it is displayed alongside the field instead of the top of the page. Don't make the user scroll the whole page looking for the next error message. Remember, someone will be spending 8 hours looking at the page you are developing. The early they understand where the error messages are displayed, the quicker they will adopt.

4. Place the buttons on the bottom as well as the top of the page.
This is a common problem in the majority of the visualforce pages. People will provide multiple sections of a form and them make sure scroll all the way up to press submit. Bad idea. Also if the user wants to just fill the required fields and then submit- which is also ok, don't make them scroll all the way down to look for the submit. Be smart, place your button on top as well as the bottom. Besides, give the user a choice and they feel included in the design.

So in summary, design user-centric system that they can adopt faster and learn quicker. Most of the Salesforce implementation fail because users do not adopt the system as they should. Make their job easier, not harder. A twenty-year experience sales person should not be bothered to learn a new system just because his job wants him to, instead, design the experience so much friendly that the said person should pick it up on the job quickly.

Hope that helps in any future design you create. If you have any other tips, share in the comments below.
Ok. Bye. For now.

And in the mortal words of a immortal machine traveling back in time, I will be back.
Share: