[SalesForce] VisualForce : Dynamically rerendered inputFields are displaying on page without labels

Background: I created a VisualForce page with the intention of embedding it inline into an Opportunity layout. I've used the standard
Opportunity controller with a controller extension. On this
page, there is a custom selectOption list with 5 values:

–None–, Tier 1, Tier 2, Tier 3, Custom

If you choose Tier 1, 2, or 3, a method runs via onchange
actionSupport, and it updates the opp based on pre-defined conditions
of each Tier, which I pull from a Custom Setting. If you choose
–None–, it updates the opp back to null for all appropriate fields. In each of these scenarios, I also re-render the pageBlockSection that
holds these fields, so that changes can be seen immediately upon
changing the selectOption.

All of this works as expected, except for the 'Custom' selectOption…


Problem: When choosing the 'Custom' option from the picklist, I set a Boolean called isCustom to true, and then the same re-render
occurs. This time however, the re-rendered section sees that isCustom is
true. In the case of this Boolean being true, I hide all of the
outputFields (via the render (true/false) param), and display inputFields instead, with the intent of
allowing the user to enter custom rate information. However, for some reason these inputFields are rendering without field Labels, and I'm not sure why, how to resolve it, or if this is a bug.


Question: Why are my dynamically rendered inputFields not displaying field Labels?


Update, 7/23/2016 5:42 PM EST :

I tried to use <apex:outputLabel /> as suggested by Santanu below, but to no avail.

When I tried <apex:outputLabel value="{!field}" />, the resulting label was displaying the API names for the fields.

When I tried <apex:outputLabel value="{!Opportunity[field]}" />, the resulting label was displaying the value of each field in the fieldSet (showing 1.65% instead of showing "Transaction Fee")

I then tried just manually creating an inputField directly below the PageBlockSection, as it was suggested that inputFields only show BOTH the label and value if they are directly below (not in a repeat). This also resulted in just the field value (with no label) even when using the standard Opportunity controller and standard Name field (shown below):

<apex:pageBlockSection columns="1" id="rateCalc" title="Rate Calculator" rendered="true" >
            <apex:form >
            <apex:inputField value="{!Opportunity.Name}" />
            </apex:form>

VisualForce Page:

<apex:page standardController="Opportunity" extensions="PDOppMSIRatePicker_CX">
    <apex:pageBlock mode="detail">
        <apex:form >
            <label><b>Select Your Pricing Tier: </b></label>
            <apex:selectList id="SelectList1"  size="1" value="{!selectedTier}" style="height:30px;font-weight:bold;">
                <apex:selectOptions value="{!SelectList1List}"/>
                <apex:actionsupport event="onchange" rerender="rateCalc,rateCalcResults" action="{!updateRates}" />
            </apex:selectList>
        </apex:form>

    <br />

        <div style="width:49%;display:inline-block;">
            <apex:pageBlockSection columns="1" id="rateCalc" title="Rate Calculator" rendered="true">
                <apex:repeat value="{!$ObjectType.Opportunity.FieldSets.PDRatePickerFields}" var="field">
                    <!-- If Records Tier is NOT set to Custom, Display outputFields with appropriate Tier data on (re)render -->
                    <apex:outputField rendered="{!!isCustom}" value="{!Opportunity[field]}" />
                </apex:repeat>
                <apex:repeat value="{!$ObjectType.Opportunity.FieldSets.PDRatePickerFields}" var="field">
                    <!-- If Records Tier IS set to Custom, (isCustom = true), Display apex:form and inputFields for adding custom rate data on (re)render -->
                    <!-- PROBLEM AREA :: WHY ARE BELOW INPUT FIELDS INSIDE THE REPEAT NOT DISPLAYING LABELS? :: PROBLEM AREA -->
                    <apex:form rendered="{!isCustom}">
                        <apex:inputField value="{!Opportunity[field]}" />
                    </apex:form>
                </apex:repeat>
            </apex:pageBlockSection>
        </div>

        <div style="width:49%;display:inline-block;">
            <apex:pageBlockSection columns="1" id="rateCalcResults" title="Rate Calculator Results" rendered="true">
                <apex:repeat value="{!$ObjectType.Opportunity.FieldSets.PDRatePickerResultsFields}" var="field">
                    <apex:outputField value="{!Opportunity[field]}" />
                </apex:repeat>
            </apex:pageBlockSection>
        </div>
    </apex:pageBlock>
</apex:page>

Controller Extension:

public with sharing class PDOppMSIRatePicker_CX {

    private final Opportunity opp;

    public PDOppMSIRatePicker_CX(ApexPages.StandardController stdController) {
        this.opp = (Opportunity)stdController.getRecord();
    }


//Begin Controller Extension Code

    // Boolean Returns True if Selected Tier = -1, otherwise Returns False
    // If True - Render inputFields on the VF Page
    // If False - Render outputFields on the VF Page
    public Boolean isCustom {
        get{
            if(isCustom == false || isCustom == null){
                Opportunity record = [SELECT Selected_Tier__c FROM Opportunity WHERE Id =: opp.id];
                if(record.Selected_Tier__c == '-1'){
                    isCustom = true;
                }
                else{
                    isCustom = false;
                }
            }
            return isCustom;
        }
        set;
    }

    // String gets the last selected Tier for this record by lazy-loading if null and pulling the value from the related record.
    // Possible Record Values: -1, 0, 1, 2, 3
    public string selectedTier{
        get{
            if(selectedTier == null){
                Opportunity record = [SELECT Selected_Tier__c FROM Opportunity WHERE Id =: opp.id];
                selectedTier = record.Selected_Tier__c;
            }
            return selectedTier;
        }
        set;
    }

    // Build List of SelectOptions for different Selectable Tiers
    // Tier 1, 2, or 3 should result in pulling data from a Custom Setting and updating the record before rerendering the rate calculator with the new data
    // Custom should result in hiding the outputFields and rendering inputFields on rerender, for entering custom rates
    public List<SelectOption> getSelectList1List(){
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('0','--None--'));
        options.add(new SelectOption('1','Tier 1'));
        options.add(new SelectOption('2','Tier 2'));
        options.add(new selectOption('3','Tier 3'));
        options.add(new selectOption('-1','Custom'));
        return options;
    }   

    // The logic that commits changes to the record depending on the selectedTier value    
    public void updateRates(){  
        List<SelectOption> options = new List<SelectOption>();
        System.debug('MM++++ Rates selectedTier: ' +selectedTier);

        if(selectedTier=='0'){
            opp.MSI_Trans_Fee__c = null;
            opp.MSI_Pricing_Rate__c = null;
            opp.MSI_Monthly_Fee__c = null;
            opp.Selected_Tier__c = '0';
            selectedTier = '0';

            update opp;
            opp.recalculateFormulas();           
        }
        else if(selectedTier=='1'){
            PDStandardRates__c rates = PDStandardRates__c.getInstance('New Customer Tier 1');
            opp.MSI_Trans_Fee__c = rates.Transaction_Fee__c;
            opp.MSI_Pricing_Rate__c = rates.Pricing_Rate__c;
            opp.MSI_Monthly_Fee__c = rates.Monthly_Fee__c;
            opp.Selected_Tier__c = '1';
            selectedTier = '1';
            System.debug('Opp Tier: ' + opp.Selected_Tier__c);
            isCustom = false;

            update opp;
            opp.recalculateFormulas();
        }
        else if(selectedTier=='2'){
            PDStandardRates__c rates = PDStandardRates__c.getInstance('New Customer Tier 2');
            opp.MSI_Trans_Fee__c = rates.Transaction_Fee__c;
            opp.MSI_Pricing_Rate__c = rates.Pricing_Rate__c;
            opp.MSI_Monthly_Fee__c = rates.Monthly_Fee__c;
            opp.Selected_Tier__c = '2';
            selectedTier = '2';
            System.debug('Opp Tier: ' + opp.Selected_Tier__c);
            isCustom = false;

            update opp;
            opp.recalculateFormulas();
        }
        else if(selectedTier=='3'){
            PDStandardRates__c rates = PDStandardRates__c.getInstance('New Customer Tier 3');
            opp.MSI_Trans_Fee__c = rates.Transaction_Fee__c;
            opp.MSI_Pricing_Rate__c = rates.Pricing_Rate__c;
            opp.MSI_Monthly_Fee__c = rates.Monthly_Fee__c;
            opp.Selected_Tier__c = '3';  
            selectedTier = '3';
            System.debug('Opp Tier: ' + opp.Selected_Tier__c);
            isCustom = false;

            update opp;
            opp.recalculateFormulas();
        }
        else if(selectedTier=='-1'){
            opp.Selected_Tier__c = '-1';
            selectedTier = '-1';
            isCustom = true;

            update opp;
            opp.recalculateFormulas();
        }
    }  
}

Example Screenshots:

After selecting Tier 2 (Working):
Tier 2 (Working)

After selecting Tier 3 (Working):
Tier 3 (Working)

After selecting Custom (Not Working – Labels not Present):
Custom (Not working)

Best Answer

<apex:OutputField/> displays label and text, <apex:inputField/> displays the both when those are directly under <apex:pageblockSection>, here those are under <apex:repeat> tag. You can add <apex:outputLabel/> before those fields when you are using isCustom logic.

You can try out something like this:

<apex:form rendered="{!isCustom}">
    <apex:outputLabel value="{!field.Label}" />
    <apex:inputField value=" {!Opportunity[field]}" />
</apex:form>

or

<apex:form rendered="{!isCustom}">
      <apex:outputLabel value="{!$ObjectType.Opportunity.fields[field].Label}"/>
      <apex:inputField value="{!Opportunity[field]}"/>
<apex:form/>

Following generic code will return the field label

<apex:outputLabel value="{!$ObjectType.CustomObject__c.Fields.Custom_Field__c.Label}" />