When Salesforce is life!

Tag: VisualForce

[Salesforce / Javascript] Visualforce tips for Javascript nerds

No secret I love Javascript.

It’s messy to the right point, it can be quick and dirty, it can be elegant, it can be wathever you are: your Javascript code can be a mirror of your personality.

And what’s better that putting together 2 things I like the most?

Yes, I’m talking about Salesforce and Javascript.

Javascript is the core of the new Lightning framework but since the birth of S-Controls (now deprecated) and Visualforce it’s been an importanto tool to expand the standard Salesforce platform.

What do you have to know before starting your Javascript journey with Visualforce?

Use zipped static resources for your scripts

Put all your JS files into a zipped static resource, this way you have aboslute control over the place where files are stored and have no problem finding them.

Use the apex:includeScript

If you use the HTML script tag the resources can be loaded more than once and this can lead to unexpected errors.

Think you are using jQuery and Bootstrap and your page loads them in sequence.

In the same Visualforce you also use a custom Visualforce component which loads jQuery itself: what’s the outcome? Bootstrap is simply erased from jQuery plugins.

The apex:includeScript component loads all the JS files only once, avoiding this kind of conflicts.

Use only one version per library

This is the same scenario of the previous paragraph.

If you load, e.g., jQuery 2 in one point and jQuery 3 on another place, this could lead to conflicts and strange behavior.

Keeping you library version on a static resouces allow you to get the right library version across all Visualforce page and components.

Use jQuery as much as you can

You’ll be using Javascript because you’ll want to create a slick, modern and responsive UI, so why reinvent the wheel?

Some good programmers still lack in jQuery knowledge, if you are one of them keep some time to study the bases of the library and I assure you won’t regret it…and you can be sure you’ll have really few problems for compatibility on different browsers.

Give all your components an ID / class name

When you develop a new Visualforce page take few minutes more that necessary to give all your components a recognizable html ID.

<page id="thePage">
 <pageBlock id="mainPB">
  <apex:pageBlockSection id="customerDataPBS" rendered="{!showCustomerData}">
   <apex:pageBlockSectionItem id="csDataNamePBSI">
    <apex:outputLabel id="csDataNameLBL">Name</apex:outputLabel>
    <apex:outputPanel id="csDataNameVAL">
     <apex:inputField id="csDataNameINP" value="{!account.Name}" />
     <apex:commandButton id="refreshCsNameBTN" 
          value="Refresh Data..." 
          action="{!refreshAccountName}"
          rerender="csDataNameVAL" />
    </apex:outputPanel>
   </apex:pageBlockSectionItem>
  </apex:pageBlockSection>
 </pageBlock>
</page>

This will ease your life if in the near future you decide to use Javascript to access the page’s markup.

Remember that IDs are automatically calculate by the Visualforce render engine, so if you want the exact ID you can use the $Component global variable, so if you want to access the apex:inputField on the previous code:

document.getElementById("{!$Component.thePage.mainPB.customerDataPBS.csDataNamePBSI.csDataNameINP}");

But I recommend not to use this way.

This is not incorrect but as you continue your Visualforce development (sometimes the customers you work with don’t know what they actually want till they want it!) you can change the UI, moving sections on the page, so the ID chain can change over time.

That’s why you can use the “ends with” operator with jQuery to get an HTML component:

var inputField = $('[id$="csDataNameINP"]');

That is easier. The only thing is that you must be sure that you only have one and only one component with that ID.

Sometimes I use class names rather that ID, so for example:

<apex:inputField class="csDataNameINP" value="{!account.Name}" />

This way I don’t care about ID generation and go directly with searching for a specific class name.

var inputField = $('.csDataNameINP');

That is even clearer (this is something I usually do and I like the syntax but it is not a best practice).

Keep coding and may the Force.com be with you!

[Salesforce / Visualforce] Handling Viewstate with Dynamic Visualforce components

I’ve written this post thanks to the help of my colleague Ivano Guerini who has found the solution to the problem I’m going to expose and written down the code you’ll see in this post.

This post is about correctly handling the viewstate when dealing with Dynamic Visualforce Components.

For those of you that have never worked with dynamic components, they are a way to create visualforce components using Apex.

For example the following piece of code returns a Page Block Section with 2 input fields on the Account record:

public Account record{get;set;}

public ApexPages.Component getDynamicComponent() {
    Component.Apex.PageBlockSection result = new Component.Apex.PageBlockSection();
    result.columns = 1;
    List sectionItems = new List();

    Component.Apex.InputField input = new Component.Apex.InputField();
    input.expressions.value = '{!record.Name}';
    result.childComponents.add(input);

    input = new Component.Apex.InputField();
    input.expressions.value = '{!record.Website}';
    result.childComponents.add(input);
}

The visualforce should be called as follows:

<apex:pageBlock>
    <apex:dynamicComponent componentValue="{!dynamicComponent}" />
</apex:pageBlock>

The page prints out a page block with a page block section with 2 input fields for the Name and Website Account’s fields.

The following code has been packed up in this Github repository for further testing and improvements.

If you wanna know more about viewstate this article is a good starting point.

Generally speaking, the viewstate is an input hidden field inside your Visualforce forms that contains all page data and that is used to post your form back to the server and forth to the page.

Too many informations, are you still there?

The problem comes when you try to use dynamic components (that can vary between post backs) and the Visualforce block your post back because of (for instance) required fields: in this specific case the dynamic components does not maintain the viewstate because the postback is blocked just before arriving on the server, so the components are created again and their status is lost.

You can test this behavior by calling the /apex/DynamicViewStateExample?id=[ACCOUNT_ID]&skip=1 (the skip parameters calls the page without the fix shown at the end of this post):

To fix this problem we need to replicate the viewstate component to re-apply the values to the different input fields after the postback has been done.

In your page we have added an apex:inputHidden component called viewstate:

<apex:dynamicComponent componentValue="{!DynamicComponent}" invokeAfterAction="true" />
 <apex:inputHidden value="{!viewState}" id="viewState" />

The trick is to use Javascript to serialize/deserialize the view states.

We use the Serialize jQuery plugin to serialize form data but we had to write our own deserialize method (see the jQuery_Deserialize static resource for more details).

This part of the code is called when there is a post back:

var closestForm = jQuery('[id$="{!$Component.viewState}"]').closest("form");
    closestForm.on("submit", function(event) {
        //serialize esch component except the "viewState" component to avoid recursion
        jQuery('[id$="{!$Component.viewState}"]').val(jQuery(this).find(':not([id$=viewState])').serialize());
    });

And this part is the code that actually deserializes the “custom” viewstate and put it in the form fields:

if(closestForm.find('[id$=viewState]').val()) {
        closestForm.deserialize(jQuery('[id$="{!$Component.viewState}"]').val());
    }

This few lines of Javascript actually to the magic!

For more details on the implementation, have a look at the DynamicViewStateExmaple page and the DynamicViewStateCmp component.

[Salesforce / Visualforce] Input Lookup Custom Component

Have you ever needed a VisualForce lookup input field without using a lookup field from another “fake” object?

I did, and now I have an easy to use VisualForce component that does the trick (almost all the trick).

Here is the GitHub repository that contains the component.

The components simply replicates what the standard lookup field does, with 2 important differences:

  • We have to use a custom Apex class to store the ID value (simple data types as String or ID are passed by value rather than reference, so it is impossibile to change the component’s parameter value on the fly, see Bob Buzzard post Updating Attributes in Component Controller)
  • If you change the value of the “name” of the lookup field and this matches more than one record, the form submission is canceled and a picklist with all the values is shown (so the user can choose the correct record)

The first class is the ID value container:

public class IDCarrier {
    public IDCarrier(){}
    public IDCarrier(ID value){
        this.value = value;
    }
    public ID value{get;Set;}
}

In your test controller, TestLookupController:

public class TestLookupController {
    public IDCarrier idValue1{get;set;}
 public IDCarrier idValue2{get;set;}
    public TestLookupController(){
        this.idValue1 = new IDCarrier([Select Id From Account Limit 1].Id);
  this.idValue2 = new IDCarrier();
    }
    public void submit(){
  //...
 }
}

You are creating 2 ID fields, one populated with a valid Account Id, the other without any value.

And now in the test page use the component:

<apex:page controller="TestPageController" >
    <apex:form >
        <apex:pageblock>
            <apex:pageBlockButtons location="bottom">
             <apex:commandButton value="SUBMIT" action="{!submit}" />
            </apex:pageBlockButtons>
         <apex:pageblocksection columns="2">
                <apex:pageBlockSectionItem>
                    <apex:outputLabel>Account lookup</apex:outputLabel>
                 <c:inputLookup sobject="Account" value="{!idValue1}"/>
                </apex:pageBlockSectionItem>
                <apex:pageBlockSectionItem>
                    <apex:outputLabel>Selected Account ID:</apex:outputLabel>
                 <apex:outputText value="{!idValue1.value}"/>
                </apex:pageBlockSectionItem>
                
                <apex:pageBlockSectionItem>
                    <apex:outputLabel>Contact lookup</apex:outputLabel>
                 <c:inputLookup sobject="Contact" value="{!idValue2}"/>
                </apex:pageBlockSectionItem>
                <apex:pageBlockSectionItem>
                    <apex:outputLabel>Selected Contact ID:</apex:outputLabel>
                 <apex:outputText value="{!idValue2.value}"/>
                </apex:pageBlockSectionItem>
            </apex:pageblocksection>
        </apex:pageblock>
    </apex:form>
</apex:page>

The component has only 2 parameters:

  • sobject: this is the Sobject API Name (with full prefix name if needed, mandatory)
  • lookup: this is the value field (of type IDCarrier). This is field is not mandatory (in case it is not set, the submit won’t set any value)

In the test page we have now 2 input lookup custom components, one of type Account and the other of type Contact:

If you click the “search” button the standard lookup search page appears (it is configurable with the standard object’s search layout options).

Once you select a new value for both input lookups and hit the SUBMIT button, the corresponding controller variables idValue1 and idValue2 are correctly updated:

If you type a different name value (without using the lookup window):

Then hit SUBMIT:

The first “%Sale%” Account found is linked to the input lookup component.
If no object is found by the query, the result is simply null (on the IDCarrier.value member).

That’s it!

[Salesforce / Apex / VisualForce] Getting rid of the “Save & New” button

In some circumstances the “Save & New” button on the standard layout is not desired.

This is an idea (there are others of this kind) to make this optional on layouts, but unfortunately it’s been freezed for years.

The simpler solution was to execute some javascript on a hone page component in order to hide every button that has the “save_new” name:
Remove Save & New button of the standard edit page.

With Summer ’15 you cannot use anymore custom home page components that contains script tags, so the hack is not valid anymore: if you try to create/edit an HTML Area Custom Component you get this info message:

This component contains code that is no longer supported. For security reasons, in Summer ’15 we will start removing non-supported code from HTML Area home page components. As a result, this component may stop working properly.

If you want to use JavaScript or other advanced HTML elements in your home page component, we recommend that you create a Visualforce Area component instead.

I had to find a solution for a client, and the “New” button override was the way.

The button I’m talking about is this one (on the Editing standard layout):

You simply have to override the “New” button on your selected objects, creating for each object a Visual Force page with a standard Controller and the following extension:

<apex:page standardController="Account" extensions="SObjectNewActionOverrideController" action="{!onLoadPage}">
</apex:page>

public class SObjectNewActionOverrideController {
    public String debug{get;Set;}
    private String SObjectPrefix = null;
    public SObjectNewActionOverrideController(ApexPages.StandardController controller){
        this.SObjectPrefix = controller.getRecord().getSObjectType().getDescribe().getKeyPrefix();
        
    }
    public PageReference onLoadPage(){
        this.debug = JSON.serializePretty(ApexPages.currentPage().getParameters());
        String retURL = ApexPages.currentPage().getParameters().get('retURL');
        //these are the conditions to understand that this is actually a "new" page
        //that comes from a previously "save" page in which the user clicked on "Save & New"
        if(ApexPages.currentPage().getParameters().get('save_new')=='1' 
           && retURL != null
           && retURL.startsWith('/'+SObjectPrefix)
           && retURL.indexOf('/', 4) < 0
           && !retURL.contains('?')
           && retURL.length() >= 15){
               PageReference pg = new PAgeReference(retURL);
               pg.setRedirect(true);
               return pg;
           }else{
               PageReference pg = new PAgeReference('/'+this.SObjectPrefix+'/e');
               for(String key : ApexPages.currentPage().getParameters().keyset()){
                   if(key == 'save_new' || key == 'sfdc.override') continue;
                   pg.getParameters().put(key, ApexPages.currentPage().getParameters().get(key));
               }
               //https://mindfiresfdcprofessionals.wordpress.com/2013/07/10/override-standard-button-in-specific-condition/
               pg.getParameters().put('nooverride','1');
               pg.setRedirect(true);
               return pg;
           }
    }
}

The code simply does a redirect to the “previously” edited record if we are coming from a save operation (and user clicks on “Save & New”), getting rid to the “New” action of the “Save & New”, or simply goes to the standard edit page (the retURL is evaluated: if it is not an object ID then goes to the New action).

As stated in the code, there are other places in which the user clicks on a “New” button but the “save_new” parameter is still passed by Salesforce (I don’t understand the reason though), but this time the user should see the “New” page.

These buttons are the “New” button on the Sobject main page (e.g. /001/o page):

And the related lists:

Comments and alternative solutions are really appreciated!

Powered by WordPress & Theme by Anders Norén