Conditional Display of Fields

,

The previous page worked well, dynamically displaying different values in a picklist based on the value of another picklist. Yes, this functionality is a recap of what is available in standard dependent picklists—so why reimplement it?

The reason to use this version of a dependent picklist is that you can expand the capabilities of this set of picklists to address a common user need. Normally, the position type for a particular position is available in its picklist. But what about those times when a user is posting a new type of position, one that is not currently available?

For a dependent picklist, this scenario is resolved by someone with developer privileges going in and modifying the values available on the dependent picklist.

With this new implementation, you can add a field to the page that allows a user to add a new position type. Of course, you do not want the user to add a new position type until they have at least looked at the currently available options.

In this section, you learn how to add a value to the Position Type list that triggers the display of an entry field for a new position type, and how to modify your controller code to save this new position type in a new record in the Position Type object.

Adding a Value to the selectList

The key to the capability you want to add to your Visualforce page is a value. This value is used to trigger the display of fields that allow a user to add a new position type for a particular department.

For the purposes of this exercise, you can use the value of Other to indicate this scenario.

1.
Return to the controller extension you created earlier in this chapter through Setup Develop Apex Classes and then the Edit choice for the positionExtension class.

2.
Modify the code that returns the selectOptions for the Position Type to include the highlighted lines of the following code:

public List<selectOption> PositionTypeOptions {get {
    List<selectOption> positionTypes =
      new List<selectOption>();
    for (Position_Type__c ptr :
        [select name from Position_Type__c pt
          where pt.Department__c =
          :position.Department__c order by Name ])
      positionTypes.add(new selectOption(ptr.id, ptr.name));
      if (position.Department__c != null) {
								positionTypes.add(new
								selectOption('other', 'Other'));}
    return positionTypes;
    }
    private set;}

This code adds another option to the list of position types, if a department has been selected. If a user selects this option, they have the opportunity to enter a new position type for the chosen department. You add the user interface for this new capability in the next section.

With this new code, you can see why you had to create the positionTypeID property to hold the ID of the Position Type. Up until this point, all the values for the positionTypeOptions have been valid ID values. You can bind the value of a selectList with only those ID values to the Position_Type__c lookup field, which only accepts an ID.

However, the value of 'other' is not a valid ID. As soon as your code attempts to associate that string with the Position_Type__c field, you will get an error. Consequently, you cannot bind the selectList to the Position_Type__c field, requiring the use of the postionTypeID property.

Before leaving this section of the code, you will add one option to the list returned to the page to help your users.

3.
Add the highlighted code to your Apex class:

public List<selectOption> PositionTypeOptions {get {
    List<selectOption> positionTypes =
      new List<selectOption>();
    for (Position_Type__c ptr :
        [select name from Position_Type__c pt
          where pt.Department__c =
          :position.Department__c order by Name ])
      positionTypes.add(new
        selectOption(ptr.id, ptr.name));
      if (position.Department__c != null) {
          positionTypes.add(new
           selectOption('other', 'Other'));
          }
 Else {
								positionTypes.add(new
								selectOption('', '
								Please select a department', true));
       }
    return positionTypes;
    }
    private set;}

This condition adds a user-friendly message to the selectList for the Position Type if there is no value for the Department selectList. The message appears in the selectList and gently guides the user towards their next action. The constructor method for this selectOption includes a third optional parameter which, if true, indicates that this option is disabled in the selectList.

Note: Limiting the power

This modification of the controller extension allows everyone to have the ability to add a new position type, a power you might not want to grant so lightly. You can easily add an if condition for adding that last value to the selectListOptions so that only certain users, or users with a certain profile, have that value in the Position type picklist. Since the presence of this value controls the rest of the operations, eliminating the Other value prevents users from accessing the ability to add a new position.


Conditionally Displaying Fields

Now that you have added a data value that allows a user to add a new position type, you have to add a field to accept the Name for the new type. However, you do not want this field to show up all the time —only when a user has chosen the Other choice.

Visualforce components have an attribute that controls their display, just as another attribute controls whether the component is enabled. With this attribute, and another re-rendering of the page, you can provide this dynamic interface to your users.

1.
Return to the Page Editor for your current Visualforce page. Since the page is now tied into the standard New action, you can get to the page by clicking on the Positions tab and then New.

2.
Add the highlighted code to the Visualforce page:

<apex:pageblockSection id="dependentPositionType"
  columns="1">
    <apex:pageBlockSectionItem >
      <apex:outputLabel value="Position Type" for="pt"/>
      <apex:panelGrid columns="2">
       <apex:actionRegion >
        <apex:outputText
           value="{!Position__c.Position_Type__c}"
           rendered="false"/>
        <apex:selectList id="pt"
          value="{!positionTypeID}" size="1"
          disabled="{!ISNULL(Position__c.Department__c)}">
            <apex:selectOptions
              value="{!PositionTypeOptions}"/>
              <apex:actionSupport event="onchange"
								rerender="dependentPositionType"
								status="typeStatus"/>
        </apex:selectList>
        </apex:actionRegion>
								<apex:actionStatus id="typeStatus"
								startText="updating form...">
								<apex:facet name="stop">
								<apex:inputField
								rendered="{!positionTypeId == 'other'}"
								required="true"/>
								</apex:facet>
								</apex:actionStatus>
      </apex:panelGrid>
    </apex:pageBlockSectionItem>
</apex:pageBlockSection>
<apex:pageBlockSection title="Position Details">

There are three different places you have added code. The first is to define an actionRegion again, as you did previously. The second is to add the actionSupport, which rerenders the pageBlockSection that contains the Position Type information.

The third area is the actionStatus. As before, you use actionStatus to display text indicated that a refresh of the form is taking place. The next set of tags define a facet. A facet is an area in a page that can contain other text or, in this case, a component. The stop facet of an actionStatus component is displayed when the action has completed – in other words, once the dependentPositionType has been refreshed. This facet will contain an inputField to receive the name of a new Position Type. But you only want to show this field if the value selected for Position Type is Other. The rendered attribute checks to see if the positionTypeId, which is the variable bound to the selectList for Position Type, contains Other. The inputField will display only if this condition is true.

Note that you have not bound your new inputField to a value in the controller yet. You will define the destination for a new Position Type in the next section, and then come back and bind the field with the value attribute.

Your Visualforce page will save without an error, but if you run it now, you will get a runtime error if you picked Other to try and show the inputField for the new Position Type. The error comes because the inputField is not yet bound to a field in the controller, which cannot be done until you add an instance of the Position_Type__c object in the controller. The next section will address this issue.

Holding the New Value

You may think of your Visualforce controller as simply a way to interact with data objects, but your controller performs an equally important role as a place where values are maintained on the Force Platform. When a user adds a value for a new position type into the dynamically displayed input field you just defined, your Visualforce controller receives that value and keeps it until your user decides to save the value to persistent storage in a Force Platform data object.

The eventual destination for this new position type is the Name field of the Position_Type__c object, so you first modify your controller extension to create a record that can be used to hold the new value.

1.
Go to edit your controller code through Setup Develop Apex Classes and select the Edit choice for your custom controller.

Voice of the Developer

While actively working on Visualforce pages and controllers, you can increase your productivity by having two tabs open, with one displaying the Page Editor for the Visualforce page and another in the Setup menu for the platform to make it easy to switch between the two environments.

2.
Add the following property declaration to the existing code:

public Position_Type__c newPositionType{
 get{
   if (newPositionType == null) {
     newPositionType = new Position_Type__c();}
   return newPositionType;
   }
 private set;
}

This property will be used to insert a new Position_Type__c record, if the user create a new position type. The get accessor checks to see if the property has been initialized with a new record instance—if not, the method creates the new instance.

3.
Save the new version of your controller code.

With this step, you have created an object to hold the name for a new Postion Type. To open the channel between the user interface of the Visualforce page and your Visualforce controller extension, you will have to go back to your Visualforce page and add the value attribute to the last inputField.

4.
Return to edit your Visualforce page. Add value="{!newPositionType.Name}" to the inputField you added in the previous section.

5.
Save your Visualforce code. Try changing the value of the Position Type Other and back to see the new fields appear and disappear from the page. The page, with the new components visible, should look like the figure below.

Figure 195. New field appearing on your Visualforce page


Your newly dynamic page is pretty nice, but you need to save the results of this pretty interface in your controller since you want to save the user’s input into Force Platform objects.

Your last task to complete this implementation is to save this new value in the Force Platform database.

Saving the New Value

The last change you make to your controller extension is probably the biggest, in terms of its impact. A standard controller, by definition, is linked to a single Force Platform object. The functionality you have added to your Visualforce page calls for more than this. Once a user adds a new Position Type, you must add a record for this new value to the Position_Type__c table and then use the ID for this new record as the value for the Position_Type__c field in the Position__c table.

From the page point of view, you do this by replacing the Save method for the standard Position__c controller. This section covers the five basic logical steps for creating a successful save operation:

Checking For a New Position Type

If your user has created a new position type, you must add a record to the Position_Type__c object to represent the new type, but you only want to take this action if a new position type is indicated.

First, create a save method in your controller extension that makes this logical test.

1.
Return to edit your controller extension class. Add the following code to the end of the existing code, just before the closing right brace:

public PageReference save() {
       }

This code defines the save method. This save procedure in your controller extension replaces the save procedure in the standard controller for the Position__c object, although your new save procedure will end up calling the default save for the object once you finish adding the specialized logic.

The save procedure returns a PageReference. The PageReference creates a URL that identifies the page sent back to the browser when the procedure completes. The default save procedure will take care of assigning a value to this return, but you will set PageReference variables explicitly later in the chapter.

2.
Modify the save method to add the logical test shown highlighted below:

public PageReference save() {
       if (PositionTypeID == 'other') {
								}
       }

Why did you check for the other value in the PositionTypeID property instead of looking for a value in the newPositionType.Name field? Your user might have selected the Other choice for the position type, added a value in the inputField for the Name, and then changed the position type back to an existing position. The inputField would not be visible, but it would still have the previous value. Since the presence or absence of other value in the PositionTypeID property is the marker for this logical state, you should test that condition.

3.
Click Quick Save to check your code for errors.

The Quick Save button parses and saves the Apex code in the edit window without sending you back to the list of Apex classes. Since you are still in the midst of developing your code, take this route to insure that you have entered the proper syntax.

Adding a New Position Type

If the user is adding a new Position Type, set the values for both fields in the record and save the record.

4.
Add the highlighted code to the new save method in your Apex class:

public PageReference save() {
       if (PositionTypeID == 'other') {
         newPositionType.Department__c =
								position.Department__c;
								insert newPositionType;}
       }

The first line of code sets the Department__c field in the newPositionType record to the value of the Department__c field in the position record. You need to add the appropriate value for department, since this value populates the selectList used in your Visualforce page.

The second line of code inserts the values in the newPositionType record into their permanent home in the Position_Type__c object.

Setting the New Position Type Lookup Value

But simply storing the new position type is not enough to satisfy the needs of your Position__c record. Remember that the Position_Type__c field in the Position__c object is defined as a lookup relationship field. A lookup relationship field takes the unique ID of the related record, not the value of the Name of that record.

This unique ID is assigned when a record is created, as you are doing with the new Position_Type__c record now. Whenever you insert a record into a Force Platform data object, the in-memory representation of that object is updated to include the new ID.

5.
Modify the code in your new save method add the highlighted line below:

public PageReference save() {
       if (PositionTypeID == 'other') {
       newPositionType.Department__c =
         position.Department__c;
       insert newPositionType;
       position.Position_Type__c = newPostionType.ID;
       }
       }

The code you currently have in your save method works for those cases when a user has added a new Position Type. What about those cases when a user has simply selected an existing Position Type?

6.
Add the highlighted else code to your savemethod.

public PageReference save() {
       if (PositionTypeID == 'other') {
         newPositionType.Department__c =
           position.Department__c;
         insert newPositionType;
         position.Position_Type__c = newPostionType.ID;
       }
       else {
								Position.Position_Type__c = positionTypeID;
								}
       }

This condition simply transfers the value from the positionTypeID into the Position_Type__c field.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.28.80