[SalesForce] Visualforce: apex:repeat and Map

In my controller I have a map of integers and strings which I want to display as checkboxes.

The controller:

public Map<Integer, String> xmlCatalogsMap {get;set;}
public Set<Integer> xmlCatalogsKeys {get;set;}

public void getXMLCatalogs() {
    String sql = 'SELECT BOID__c, Name FROM ZXMLCatalogs__c ORDER BY Name';
    List<ZXMLCatalogs__c> result = Database.query(sql);
    Map<Integer, String> xmlCatalogsMap = new Map<Integer, String>();

    for (ZXMLCatalogs__c c : result) {
        xmlCatalogsMap.put(Integer.valueOf(c.BOID__c), c.Name);
    }

    Set<Integer> xmlCatalogsKeys = xmlCatalogsMap.keySet();
}

getXMLCatalogs() is called from constructor.

Now I want to display a checkbox for each integer/string pair. Integer/key should be the checkbox value and the string should be the label:

<apex:repeat value="{!xmlCatalogsKeys}" var="i">
    <apex:pageBlockSectionItem>
        <apex:inputCheckbox label="{!xmlCatalogsMap[i]}" value="{!i}" html-name="CatalogId" />
    </apex:pageBlockSectionItem>
</apex:repeat>

I read
how to display map on vf page in salesforce
and
How to reference a map's keySet() and individual map elements within Visualforce? Get 'Unknown function' error

When I compile with Sublime/Maven I always get the below error without line number:

Unknown property 'i'

Why can't I use i (or any other variable name) as a variable?

Best Answer

In the line:

<apex:inputCheckbox label="{!xmlCatalogsMap[i]}" value="{!i}" html-name="CatalogId" />

value attribute should be Boolean. So that checkbox can be marked as check or uncheck.

Currently it's Integer. That's why it is showing error.

To fix this problem, set up a map of Integer to Boolean, then bind the checkbox to that instead.

public Map<Integer, Boolean> xmlCatalogsChecked { get; set; }

public void getXMLCatalogs() {
    // Query omitted
    xmlCatalogsChecked = new Map<Integer, Boolean>();
    for (ZXMLCatalogs__c c : result) {
        xmlCatalogsMap.put(Integer.valueOf(c.BOID__c), c.Name);
        // Assign default state
        xmlCatalogsChecked.put(Integer.valueOf(c.BOID__c), false);
    }
}

<apex:inputCheckbox label="{!xmlCatalogsMap[i]}" value="{!xmlCatalogsChecked[i]}" 
    html-name="CatalogId" />

Update based on Comments

Main issue in your code is this line at getXMLCatalogs() method which is initializes the map and makes that empty.

Map<Integer, String> xmlCatalogsMap = new Map<Integer, String>(); 

I have create apex class and pages just like you and it is working correctly.

Apex class

public class DealerController
{
    public Map<Integer, String> xmlCatalogsMap {get;set;}
    public Map<Integer, Boolean> xmlCatalogsChecked { get; set; }

    public Set<Integer> xmlCatalogsKeys {get;set;}

    public DealerController()
    {
        getXMLCatalogs();
    }

    public void getXMLCatalogs() {
        xmlCatalogsKeys = new Set<Integer>();

        String sql = 'SELECT Dealer_Number__c, Name FROM Dealer__c ORDER BY Name';
        List<Dealer__c> result = Database.query(sql);

        xmlCatalogsMap = new Map<Integer, String>();
        xmlCatalogsChecked = new Map<Integer, Boolean>();

        for (Dealer__c c : result) {
            xmlCatalogsMap.put(Integer.valueOf(c.Dealer_Number__c), c.Name);
            // Assign default state
            xmlCatalogsChecked.put(Integer.valueOf(c.Dealer_Number__c), false);
        }
         xmlCatalogsKeys = new Set<Integer>(xmlCatalogsMap.keySet());


    }

}

Visualforce

<apex:page id="dealerPage" controller="DealerController" action="{!getXMLCatalogs}">
    <apex:form >
    <apex:pageBlock >
    <apex:pageBlockSection >
    <apex:repeat value="{!xmlCatalogsKeys}" var="i">


            <apex:inputCheckbox label="{!xmlCatalogsMap[i]}" value="{!xmlCatalogsChecked[i]}" 
            html-name="CatalogId" />


    </apex:repeat>
    </apex:pageBlockSection>
    </apex:pageBlock>
    </apex:form>
</apex:page>

Result checkbox