Popup action confirmation with Apex parsing in Visualforce

Posted by Craig Probus
Craig Probus”

 keep-calm-and-try-coding

Visualforce is a very powerful tool in the Salesforce1 platform arsenal but, as with any technology based on the client/server model of the http protocol, it has certain limits as to what it can and cannot do. There are always programmatic ways around these limits of course, and each carries with it varying degrees of complexity, pros, and cons.

 

In this post we will resolve a common use case that Visualforce, and in fact any web application, simply cannot perform in a single operation but most users expect to occur seamlessly. l also try and minimize our use of non-Visualforce components to keep our solution as “In the Box” as possible. This is very important for a couple of reasons:

 

  1. The more external libraries and code we leverage the more likely that some future update to Salesforce itself will break our solution
  2. Any subsequent developers who are tasked with updating and maintaining our code in the future are less likely to be left scratching their heads and spending hours in front of Google trying to figure out exactly what the heck it was that we did

 

Enough introduction, on to the code!

 

In this scenario, we have a record that needs to be saved but unfortunately requires some validation that would be difficult to perform anywhere but in Apex code. Also this validation won’t necessarily reject the save, but we’ve been required to alert the user to a particular condition of we detect it and get their approval before we proceed with the save.

 

Obviously, this is going to take more than one trip to the server, but thanks to the wonderful apex:actionFunction component and just a dash of JavaScript (you didn’t think we were going to completely dodge that bullet did you?) we can simulate a very desktop experience for the user and bask in the accolades of our users!

 

Just a note: though you don’t truly need to, I highly recommend that you leverage jQuery if you’re going to be using any JavaScript in your Salesforce Org. I took the simple route and simply saved a minified jQuery library as a .txt file and then saved as a static resource called “jQuery” in my Org.

 

The implementation here is quite simple, simply create a new class in your Org called “PopupTestController” and paste the following code into it:


 

public class PopupTestController {
   public Boolean causeValidationWarning {get; set;} // Just used for controlling the test behavior from the ui. Not a part of the solution.
   public String validationWarning {get; set;}

   // Validates the record (or whatever) is good. If it is then we call save, else we set a warning message that
   // tells the ui to display a javascript popup box to the user confirming they really want to proceed.

   public PageReference ValidateAndSaveRecord() {
      PageReference result = null;

      // Your actual validation code would go here ...

 

   if(causeValidationWarning){

         validationWarning = 'This is a validation warning, hit Ok if you\'re sure you want to proceed.';

   }

   else {

         validationWarning = '';

         result = SaveRecord();

   }

   return result;

   }

 

   // Clears the validation warning so the ui won't try and display a confirmation box to the user

   public void clearvalidationWarning(){

          validationWarning = '';

   }

 

   // Actually saves the record and then performs some post save function. Could be anything from displaying a save message (which means

   // we'd need to clear the validation warning to keep the confimation pop from appearing), or it could even be a redirect somewhere else.

   public PageReference SaveRecord() {

          ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.CONFIRM, 'Save Complete!', 'And I totally could have redirected you or something.');

          ApexPages.addMessage(myMsg);

          clearvalidationWarning();

          return null;

   }

 

   // Just to prove that our Validation & Save logic won't affect other functionality

   public PageReference DoSomething() {

          ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.INFO, 'I did some other work.');

          ApexPages.addMessage(myMsg);

          return null;

   }

}

 

Then create a Visualforce page and paste this code into it:

 

<apex:page controller="PopupTestController" id="pg" showHeader="true" sidebar="true">

   <apex:includeScript value="{!$Resource.jquery}"/>

 

   <script>

       var j$ = jQuery.noConflict(); //Needed for jQuery usage

 

       j$(document).ready(function(){          

           var validationWarningMsg = "{!validationWarning}";

           if(validationWarningMsg != ''){ // There was a validation warning, make sure the user still wants to save  

               if(confirm(validationWarningMsg)){

                   saveRecordAction();

               }

               else {

                   clearvalidationWarningAction();

               }

           }

       });

   </script>

 

   <apex:form id="myForm">

         <apex:pageMessages />

         <apex:actionfunction name="saveRecordAction" action="{!SaveRecord}" />

         <apex:actionfunction name="clearvalidationWarningAction" action="{!clearvalidationWarning}" />

 

         <apex:pageBlock tabStyle="Account">

           <apex:pageBlockButtons >

             <apex:commandButton value="Save Record" action="{!ValidateAndSaveRecord}" />

             <apex:commandButton value="Do Other Work" action="{!DoSomething}" />

           </apex:pageBlockButtons>

 

         <apex:pageBlockSection title="Stuff" columns="1" >

           <apex:inputCheckbox value="{!causeValidationWarning}" label="Cause a validation warning" />

         </apex:pageBlockSection>

       </apex:pageBlock>

   </apex:form>

</apex:page>

 

Now if you navigate to your new page which will be located at /apex/PopupTest you should see something like this:

Craig_Blog_Image_1 

 

From here you can simply test out the functionality;

 

  • Clicking on “Save Record” will save our imaginary record
  • Checking the checkbox will cause our save to encounter the warning condition that requires to verify with out user that they still wish to proceed with the save.
  • The other work button is simply to show that our save and validation logic won’t adversely affect other buttons or functionality regardless of what state we’re in.

 

After clicking save without encountering the warning condition:

 Craig_Image_2_

 

After clicking save with encountering the warning condition:

 Craig_image_3_

 

If you test out the page you’ll discover as expected that clicking on “Ok” here completes the save and “Cancel” cancels it, leaving us on our page.

 

Now, what did we do?

 

We took advantage of the useful apex:actionFuction, a handy little control provided by Salesforce that makes short work of any apex we wish to make.

 

If you reference back to the PopupTest page you see that our “Save Record” button calls into ValidateAndSaveRecord() in our controller, a function designed to first inspect our data before calling into a dedicated SaveRecord() method.

 

<apex:commandButton value="Save Record" action="{!ValidateAndSaveRecord}" />

 

The code in this sample is a bit contrived of course, but if ValidateAndSaveRecord() does detect a warning condition, it sets a String property on the controller and returns a null PageReference to our Visualforce page. This causes the page to simply post back to itself and that’s where our JavaScript comes in:

 

j$(document).ready(function(){          

   var validationWarningMsg = "{!validationWarning}";

   if(validationWarningMsg != ''){ // There was a validation warning, make sure the user still wants to save  

       if(confirm(validationWarningMsg)){

           saveRecordAction();

       }

       else {

           clearvalidationWarningAction();

       }

   }

});

 

Thanks to jQuery, this code runs every time the page is loaded, on the initial load and on any post back. The function is simple, if the warning property of the controller is not blank then that text is displayed to the user in a confirmation dialog.

 

Clicking Ok causes an Ajax call via our actionFunction “saveRecordAction”:

 

<apex:actionfunction name="saveRecordAction" action="{!SaveRecord}" />

 

And clicking cancel causes an Ajax call via our “clearvalidationWarningAction” actionFunction to clear out the warning message and ensure that no subsequent postbacks cause the popup to appear:

 

<apex:actionfunction name="clearvalidationWarningAction" action="{!clearvalidationWarning}" />

 

And that’s really all there is to it! The apex:actionfunction allows direct JavaScript calls into Apex controller methods just as though they were native JavaScript functions themselves, and we leveraged this to turn our save process into a two step validation warning and save routine.

 

Actionfunction can actually do a bit more than even this so be sure to read up on it: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_actionFunction.htm. Now go wow some users!

Find out how we can help. Request a free consultation:

FREE CONSULTATION

Subscribe to Blog