How to convert apex:pageMessages to be slds style

The problem

If you haven’t done so already, now is the time to seriously think about converting your existing Visualforce pages into lightning. One of the issues I have encountered during the process is to convert <apex:pageMessages/> section into slds look and feel:

pagemessages

Your actionFunction or commandButton controller side code is usually like this below:

public class ConvertPageMessagesController{
    public ConvertPageMessagesController(){
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.FATAL,'Please enter Account name'));
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR,'Please enter Account number'));
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.WARNING,'Please enter Account phone'));
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.INFO,'Please enter Account site'));
        ApexPages.addmessage(new ApexPages.message(ApexPages.severity.CONFIRM,'Please enter Account industry'));
    }
}

And in VF pages, we display them in <apex:pageMessage/> section. However, it is hard to style it directly.

We can walkaround this by using a errorMsg property in the controller, and severityLevel as another property. Then we will be able to display them based on those two values. However, if we do it that way, the code will inevitable be long and tedious. So how do we resolve it?

A little bit hacking into Visualforce page way

This approach is coming from Vishnu Kumar’s blog.

css:


<style>
.msgIcon {
    display: none!important
}
.customMessage * {
    color: #fff!important
}
.customMessage {
    margin: 5px 0!important;
    max-width: 1280px;
    opacity: 1!important;
    width: 100%;
    font-size: 12px;
    border: 0px;
    padding-left: 10px;
}
.message {
    opacity: .1
}
</style>

Javascript

<script>
    $(document).ready(function(){
       overridePageMessages();    
    });
        
    function overridePageMessages(){    
        var textureEffect = '';
        //Uncomment below line for texture effect on page messages
        //textureEffect = 'slds-theme--alert-texture';
                     
        $('.warningM3').addClass('slds-notify slds-notify--toast slds-theme--warning customMessage '+textureEffect);          
        $('.confirmM3').addClass('slds-notify slds-notify--alert slds-theme--success  customMessage '+textureEffect);    
        $('.errorM3').addClass('slds-notify slds-notify--alert slds-theme--error customMessage '+textureEffect);                  
        $('.infoM3').addClass('slds-notify slds-notify--toast customMessage '+textureEffect);    
                         
        $('.errorM3').removeClass('errorM3'); 
        $('.confirmM3').removeClass('confirmM3'); 
        $('.infoM3').removeClass('infoM3');   
        $('.warningM3').removeClass('warningM3');  
    }
</script>

Call overridePageMessages() in your document.ready() function or in your onComplete method of actionFunction or commandButton.

So this is a little bit hack into Visualforce page. Does it mean it is unsafe to use this method?

Well, theoretically, yes. Salesforce can change the implementation of Visualforce page without notice. However, I haven’t seen them get changed frequently in the past. Also, Visualforce is not evolving fast at this moment as well. I would say it is quite safe to use this approach.

Eric’s approach without hacking into VF page

Eric showed us another approach without using any hacking. It uses a little bit more code. But doesn’t need to hack into Visualforce page’s implementation. Personally, I would recommend this a little bit more. But it really depends on you which one you like.

Class used by all the controllers:

public abstract class VF_Messages_Abstract {
    public void createError(ApexPages.Severity s, String message) {
        ApexPages.addMessage(
                New ApexPages.Message(
                        s, string.escapeSingleQuotes(message.escapeJava())
                )
        );

    }

    /**@description Indicates if a custom message is present*/
    public boolean hasMessages {
        get {
             return ApexPages.hasMessages();
        }
    }

    /**@description The custom error message */
    public String errorMessage {
        get {
            if (hasMessages) {
                return ApexPages.getMessages()[0].getDetail();
            }

            return null;
        }
    }

    /**@description The type of message: 'error' or 'success' */
    public string alertType {
        get {
            if (hasMessages) {
                return ApexPages.getMessages()[0].getSeverity() == ApexPages.Severity.CONFIRM ? 'success' : 'error';
            }

            return 'error';
        }
        private set;
    }
}

 

 

Message Toast

    <!-- ERROR ALERT DIV -->
    <apex:outputPanel layout="block" id="msg_block" style="display: none;">
        <div id="err_wrapper"
             class="slds-notify slds-notify--alert slds-theme--{!alertType} slds-theme--alert-texture"
             role="alert">
            <h2>
                <div xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
                    <svg aria-hidden="true"
                         class="slds-icon icon-text-email slds-icon--small slds-m-right--x-small">
                        <use xlink:href="{!URLFOR($Resource.SLDS, '/assets/icons/utility-sprite/svg/symbols.svg#' + if(alertType = 'success','check','ban'))}"></use>
                    </svg>
                    <span id="err_text"></span>
                </div>
            </h2>
        </div>

    </apex:outputPanel>


Helper Panel

        <!--APEX VARIABLES DIV-->
        <apex:outputPanel id="post_processing">

            <script>

                var hasMessages = {!hasMessages};
                var errorMessage = "{!errorMessage}";
                hideProcessing();
                checkMessages();

            </script>

        </apex:outputPanel>

Check Messages Code (Using jQuery)

function checkMessages() {
    if (hasMessages) {
        $('#err_text').html(errorMessage);
        $('[id$=msg_block]').show();
    } else {
        $('[id$=msg_block]').hide();
    }

}

The buttons, action functions, etc rerender the post_processing and msg_block

Creating an error In the controller when you catch or want to display an error you simply:

createError(ApexPages.Severity.[ERROR | CONFIRM],YOURMESSAGEHERE);
This allows you to control the messages, when to display it and which theme to show.

Note: The xmlns= on the div containing the SVG is a MUST as if you try to rerender without it the page will simply stall. Important trick to remember for anytime you are re rendering a container containing an SLDS SVG

Why do I prefer this method a little bit more?

Because:

  1. You don’t need to hack into VF page implementation. Therefore you don’t need to worry about Salesforce suddenly changed the implementation. The chance is small. However, there is still a chance.
  2. The approach can easily adjust the error implementation type, you can easily change it into alert, toast or an error dialog.

However, it really depends on you which one do you prefer. If you have a better approach, leave a comment or send me an email.

Next Post

Convert Visualforce tags into SLDS look and feel

Subscribe to Sfdcinpractice

Subscribe to get the latest blogs and tutorials of sfdcinpractice. No spam, no trash, only the awesome posts from sfdcinpractice. 

Leave a Reply

Your email address will not be published / Required fields are marked *