Saturday 26 February 2011

Visualforce Field Sets

Here at BrightGen, we've always tended to advise customers that replacing edit pages with Visualforce should be a last resort, as it means coding is required if additional fields are created on the sobject.  With the advent of Field Sets in Spring 11, this becomes much less of an issue.

Field sets are well documented in the Salesforce help, so I won't reproduce any of that here.  Instead, here's an example using field sets to create an edit page with additional Visualforce functionality.

Firstly, I've created two Field Sets on the Account standard object.  The first is for general fields that I'll show at the top of the record:


While the second is for Address-specific fields:


Next I create my Visualforce page. The key markup is as follows:

<apex:pageBlock mode="maindetail" title="Account Edit">
        <apex:pageBlockButtons >
           <apex:commandButton value="Cancel" action="{!cancel}"/>
           <apex:commandButton value="Save" action="{!save}"/>
        </apex:pageBlockButtons>
        <apex:pageBlockSection title="General">
           <apex:repeat value="{!$ObjectType.Account.FieldSets.General}" 
                    var="field">
              <apex:inputField value="{!Account[field]}" />
           </apex:repeat>
        </apex:pageBlockSection>
        <apex:pageBlockSection title="Address">
           <apex:repeat value="{!$ObjectType.Account.FieldSets.Address}" 
                    var="field">
              <apex:inputField value="{!Account[field]}" />
           </apex:repeat>
        </apex:pageBlockSection>
        <apex:pageBlockSection title="Bar Chart">
    <div id="barchart" style="width: 450px; height: 25px;"></div>
 </apex:pageBlockSection>
     </apex:pageBlock>

Using the field set is as simple as accessing it from the $ObjectType global variable and iterating the fields:

<apex:repeat value="{!$ObjectType.Account.FieldSets.Address}" 
           var="field">
      <apex:inputField value="{!Account[field]}" />
   </apex:repeat>

The additional Visualforce functionality is a simple Dojo barchart, which is drawn in by Javascript into the barchart div.

Here's the generated page:


As an Administrator, if I then decide that I'd like to add the Industry field to the page.  I simply edit my General Field Set to add the field to the end of the set, refresh the page, and the new field is present with zero coding effort:


I've already used this in one solution that combines record creation with embedded searching capabilities.

23 comments:

  1. Is there a way you can pass a fieldset name from a controller extension to the apex:repeat in the above example?

    ReplyDelete
  2. Not as far as I know. There's a Force.com blog post on field sets at http://blog.sforce.com/sforce/2011/02/using-field-sets-in-spring-11.html and the author states that fieldset metadata is not available in Apex at present.

    ReplyDelete
  3. Sorry for my English. In the sets of fields could put Will masks or certain values​​, for example, a single field number in the Visualforce code without having to put it when you create a field in salesforce?. It would be like when we put the Required = (var.requiered) to a InputField to only leave the fields that are mandatory salesforce. Or put them in serious SOLUTIONS salesforce to create the fields and create code so that only leaves predeteminados values ​​according to the profile or page layout. Thanks

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Do you know how to get this to work with web to lead? Is it possible with the use of an extension to the standard Lead controller?

    ReplyDelete
  6. You won't be able to use this for web to lead, as that is an HTML form that hits a particular servlet rather than Visualforce.

    You could certainly create a lead capture visualforce page, but you'd have to make this available via an unauthenticated Force.com site for it to work like web to lead.

    ReplyDelete
  7. I have a field set, but one is input field other is plain output text field. How can I have these 2 fields in a field set?

    ReplyDelete
    Replies
    1. Field sets just contain fields. You add the input/output behaviour on the page. Maybe you should have two field sets - one for inputs and one for outputs,

      Delete
    2. This comment has been removed by the author.

      Delete
    3. @Bob: That's generally correct, but I think you could make this work if you added some logic to the VF Page (and/or its controller extension) that would tell you if a field should be input or output. For example, you could probably wrap them into an , and always render just one field, with rendered="{!f.Label=='JustShowMe'}", rendered="{!f.readOnly}", or something like that (for the latter, you would have to get the fields from the controller via an extended List method). http://www.salesforce.com/us/developer/docs/pages/Content/pages_dynamic_vf_field_sets.htm should get @Mitesh on the right path. I've never tried this, but I think I will. Stay tuned...

      Delete
    4. darn, the tags were removed: I meant to say: wrap them into an outputPanel and extend "List < Schema.FieldSetMember > " method.

      Delete
  8. Are there any known limitations as to what the end user can and cannot do with field sets? The questions that come to mind are:
    - can the customer's admin add new fields that were created at the customer's site, outside of the managed package, so that these are also rendered on the packaged VF Page?
    - is there a way to prevent customers from removing specific fields, because they may be tied to some internal logic?

    ReplyDelete
    Replies
    1. I just found out myself: end users can indeed add their custom fields to one of our field sets and have them properly rendered on our VF Page (which actually is the whole point of using fields sets for me). There's an important thing to know about the "Required" flag on fields in a field set, though: end users can remove required fields from the field set, but they can't change the field's required flag from true to false. But of course you could offer two field sets, if you need to be flexible: one having a field in it as required, and another where the flag for the same field is set to false. This would allow the end user to add the field to one set, and remove it from the other, as needed. This may force you into some awkward VF design, though.

      Delete
  9. Is it possible to show a custom field label instead of object field label, Say I have created a filed with a label as 'Name', but I want to display the label as 'First Name' in VF by using fieldsets

    ReplyDelete
  10. I tried your example and got the following error:

    Error: apex:commandButton must occur between tags

    ReplyDelete
    Replies
    1. That isn't a full example - the snippet is the key markup, so you'll need to wrap it in apex:form tags (and possibly others).

      Delete
  11. I created fields using metadata api in an visualforce page how to display these fields dynamically in an visualforce page.

    please help me...

    ReplyDelete
  12. I can't find a way to insert the field values of the parent object that are being used in the fieldset on the child object. Below is my code and I get the null values. I can only successfully insert the values in the Job object. Not sure if my approach is correct to use the parent object fields in the child fieldset.


    public with sharing class fieldsetJobApplication
    {
    // Job object has a lookup to the Candidate object
    // The fieldset is on the Job object and is referring few fields on the Candidate object
    // From the VF page on insert the values into the Job object are inserted fine but the fieldset values on the Candidate object remain null

    public Job__c jA {get;set;}
    public Candidate__c jC {get;set;}

    public fieldsetJobApplication()
    {
    jA = new Job__c();
    jC = new Candidate__c();
    }

    public PageReference save()
    {
    assignValues();

    // Insert Candidate record
    insert jC;
    // Provide the parent Id to child record for reference
    jA.Candidate__c = jC.Id;

    // All below show as null values on System.debug
    System.debug('jA.Interviewer__c : ' + jA.Candidate__r.Interviewer__c);
    System.debug('jA.Start_Date__c : ' + jA.Candidate__r.Start_Date__c);
    System.debug('jA.Education__c : ' + jA.Candidate__r.Education__c);

    System.debug('jC.Interviewer__c : ' + jC.Interviewer__c);
    System.debug('jC.Start_Date__c : ' + jC.Start_Date__c);
    System.debug('jC.Education__c : ' + jC.Education__c);

    insert jA;

    return new pagereference('/'+jA.id);
    }

    public List getFldsJA()
    {
    return SObjectType.Job__c.FieldSets.JA_Fieldset.getFields();
    }
    }

    // VF Markup














    ReplyDelete
  13. This comment has been removed by the author.

    ReplyDelete
  14. How to render fieldsets in visualforce page when checkbox is clicked ? If checkbox is checked it should render fieldset "propername" else it should render fieldset "Unusualname".

    Both fieldset are created on Standard Object "Contact".

    ReplyDelete
  15. Hi Bob, quick question. If a field set contains a reference and it is loaded into columns using repeats, that reference field displays as a hyperlink. Is there any way to remove the hyperlink portion and just keep the text?

    ReplyDelete
    Replies
    1. I figured it out, it looks like you can access all the fields in the references in the field set.

      Delete