Hiding Custom Buttons on a VisualForce Page

mgsmith | Friday, October 16th, 2009 | 13 Comments »

Sorry it’s been so long time since my last blog post. Life and work just seem to get in the way.

I recently wanted to setup some custom buttons that could be dynamically hidden or renamed on the page. As you probably know, Salesforce.com does not currently have the ability to hide buttons on a page layout. However, it can be done through a combination of VisualForce and JavaScript.

Idea to vote on: http://ideas.salesforce.com/article/show/101209/Limit_the_Visibility_of_a_Custom_Button

The most important thing to note here is that this can only be done on a VisualForce page. It’s not possible to hide or take any actions on custom buttons that are on a standard page. This is due to cross-site scripting limitations of all browsers that prevent JavaScript from modifying the DOM of a window at another domain. You’ll see why as we get into the coding.

To start, I’ve taken a simple custom object and created an even simpler VisualForce page to use for the VIEW. Once created, just override the VIEW option with this page.

<apex:page standardController="Application__c" title="Application For {!Application__c.Contact_Name__c}" >
    <apex:Detail subject="{!Application__c.ID}" relatedList="true" />
</apex:page>

At first, the result is visually the same. Now let’s add a custom button to the page.

Screenshot_NewButton

In this case, I named the button “Update_Status”. The ‘Name’ is critical to modifying the button in the VisualForce. Though, the name must always be lowercase in your VisualForce page. For example, even though I have “Update_Status” as the Name here, my VisualForce code will reference “update_status”.

Now comes the fun. By adding some JavaScript to the VisualForce page you can manipulate the button – hide it, disable it, or even change the button label.

<script>
function hideButton(btnName) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i < buttons.length; i++) {
      buttons[i].className="btnDisabled ";
      buttons[i].disabled=true;
      buttons[i].type='hidden';
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}

function renameButton(btnName, newTitle) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i < buttons.length; i++) {
      buttons[i].value=newTitle;
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}
</script>

We’ll start with the above two functions. By passing in a button name to the hideButton() function we can hide it on the page. Passing in the same button name and a new title to renameButton() will change the button label on the page. Below is my full VisualForce page code:

<apex:page standardController="Application__c" title="Application For {!Application__c.Contact_Name__c}" >
    <apex:Detail subject="{!Application__c.ID}" relatedList="true" />

<script type="text/javascript">
// The code below is executed as soon as the page loads. Based on the value of the Status__c field
// it either hides or renames the update_status button
if ('{!Application__c.Status__c}' == 'Submitted') renameButton("update_status", "Mark as In-Review");
if ('{!Application__c.Status__c}' == 'In-Review') hideButton("update_status");
if ('{!Application__c.Status__c}' == 'Deposit Pending') renameButton("update_status", "Confirm Deposit Received");
if ('{!Application__c.Status__c}' == 'Deposit Received') hideButton("update_status");
if ('{!Application__c.Status__c}' == 'Approved') hideButton("update_status");
if ('{!Application__c.Status__c}' == 'Rejected') hideButton("update_status");

function hideButton(btnName) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i < buttons.length; i++) {
      buttons[i].className="btnDisabled ";
      buttons[i].disabled=true;
      buttons[i].type='hidden';
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}

function renameButton(btnName, newTitle) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i < buttons.length; i++) {
      buttons[i].value=newTitle;
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}
</script>

Screen captures of the page with button showing and hidden:

ScreenCapture_WithButtonScreenCapture_WithoutButton

Share

13 Comments

  1. frasuy says:

    Nicely done. Pretty slick!

  2. I have been turning buttons on and off using the rendered= property, and by making the button name a value.

    So in the controller, you have variables

    Boolean myButtonOn
    String myButtonName

    You set these in the controller.

    Then, in the Apex page you have

    <apex:commandbutton
    rendered="{!myButtonOn}"
    action="whatever"
    value="{myButtonName}"

    Are there any advantages that you see to either method?

  3. mgsmith says:

    True. I use that when I’m placing the buttons manually onto a completely custom VF page, but in this case I wanted to use the standard Custom Buttons that are defined on an Object and added to a Page Layout. This way the buttons all flow together when using the apex:Detail tag. I think to use the apex:commandButton tag, you’d have to define a new apex:PageBlock above the standard Detail page. Both methods can work.

  4. Kohnejo says:

    It doesn’t work on IE.

  5. Kohnejo says:

    And the reason of it is the “type=’hidden’”. Without this works fine if u dont want them to dissapear, just dont be enabled.

    In my case is fine. Thanks!

  6. AC says:

    Thanks for the blog entry. I’m new to Salesforce and I’m trying to accomplish this. Is it possible to include the full listing for the Custom Button? I’m getting a “button is not defined” message in my attempts to recreate this. Thanks!

  7. mgsmith says:

    AC,

    There is a screen capture of the custom button settings at the top of the post. Feel free to eMail me directly if you need help getting this working in SalesForce.

    Mike

  8. Guy says:

    Hi Mike,
    out of the different solutions available on the net, this is in my opinion the best and cleanest. Works like a charm.
    Thanks for sharing!
    Guy

  9. Anutosh says:

    Thanks for the post. Helped me a lot.

  10. Guy says:

    Too bad my inline editing does no longer function now.. Any solution for that?

  11. Guy says:

    so simple.. in order to re-enable inline editing I just had to add inlineEditing=”true” to the apex:detail element..

  12. Jesica says:

    Hi, I’m trying to include a custom button and hiding/displaying It according to an status field value in Cases Tab.
    I’m not sure where and how I can include the VisualForce page in order It to be loaded during Cases Tab loading time.
    Any hints on how making that work?

  13. mgsmith says:

    Jesica,

    Adding a VisualForce page to a page layout is done on the Page Layout editor, however it likely won’t work now. VisualForce pages load from a different domain than the standard page layout. For example, the URL for a standard layout might be something like https://na1.salesforce.com/001W0000001xZkK. An embedded visualforce page on that page layout might come from https://c.na1.visual.force.com. Browser security will prevent javascript on the visualforce page at https://c.na1.visual.force.com from modifying any of the page elements on the parent page at https://na1.salesforce.com.

    I know it’s a bit on the technical side, but basically you can’t hide/modify buttons on a standard page layout this way.

    That said, it can be done if you override the VIEW for your object with a VisualForce page and use the tag to display the standard page layout within the VF page. In that method, all of the content is on the same domain and you are able to use JavaScript to modify any page element, even on the standard page.

    Best Regards,

    Mike

Leave a Reply