[SalesForce] Displaying map in Visualforce – key with List> values

I am trying to use a data map to display information in a visualforce table. I have tried many of the suggestions in similar questions but no luck yet. My relevant controller code follows:

Public Map<User,List<List<ForecastValues>>> DirectReportValueMap{ get; set; }
public class forecastItems{
    public List<OpportunityLineItem> all { get; set; }
    public List<OpportunityLineItem> noSchedule { get; set; }
    public List<OpportunityLineItemSchedule> schedule { get; set;}
}

Public static forecastItems initializeForecastItems(){ 
        forecastItems fi = new forecastItems();
        fi.all = new List<OpportunityLineItem>();
        fi.noSchedule = new List<OpportunityLineItem>();
        fi.schedule = new List<OpportunityLineItemSchedule>();
        return fi;
    }
Public static forecastValues initializeForecastValues(){
        forecastValues fv = new forecastValues();
        fv.quantity = 0; fv.revenue = 0;
        return fv;
    }
Public List<forecastValues> initializeforecastCategValues(){
        forecastCategValues = new forecastValues[5]; /// one for each category: closed, commit, bestCase, Pipeline, TOTALS \\\
        for (integer i = 0; i < forecastCategValues.size(); i++){
            forecastCategValues[i] = initializeForecastValues();
        }
        return forecastCategValues;
    }
 Public List<List<forecastValues>> initializemonthlyValues(){
        List<List<ForecastValues>> mV = new List<List<ForecastValues>>();
        for (integer i = 0; i < 6; i++){ /// one for each period in forecasting range: 1-6 \\\
            mV.add(initializeforecastCategValues());
        }
        return mV;
    }


Public void UpdatePage(){
    directReports = [SELECT Id, Name, UserRole.Name FROM User WHERE Id IN :directReportIds];
        for(User u:directReports){
            List<List<ForecastValues>> dRMonthlyValues = initializemonthlyValues();
            forecastItems drForecastItems = initializeForecastItems();
            drForecastItems.all = DirectReportLIMap.get(u.Id);
            drForecastItems = splitForecastItemsbySchedule(drForecastItems);
            dRMonthlyValues = GetForecastValues(drForecastItems);
            DirectReportValueMap.put(u,dRMonthlyValues);
        }
System.debug(DirectReportValueMap);
}

I am trying to display the DirectReportValueMap, where the user name is in one column and each value in the List> is shown in the following column (I'm not too concerned about styling at this point, I just would like to see it displayed.) I have used system.debug(DirectReportValueMap) to ensure that the map is filled correctly.

I have tried using the following visualforce code to display the data, but it doesn't display anything.

    <apex:outputPanel>
    <apex:repeat value="{!DirectReportValueMap}" var="key" >
            <apex:pageBlock>
                <apex:outputText value="{!key.Name}" />
                <apex:pageBlockTable value="{!DirectReportValueMap[key]}" var="valueList" >
                    <apex:column value="{!valueList}"/>
                </apex:pageBlockTable>
            </apex:pageBlock>
        </apex:repeat>
    </apex:outputPanel>

Does anyone have and advice how to make this work? I am stumped!

for context, I am basically rewriting the built-in 'Customizable Forecast' tab, where at this point in my page I am collecting the current users direct reports as the map keys and calculating their individual forecast data per month. I chose to use a map so I can pass the entire mess of data from one function to another. Also, I was hoping that a map would allow me to display all of this information in a single nested table. Since the number of direct reports varies by user, I'm not sure how to initialize the right number of public lists to be able to access in my VF page

Best Answer

Using a dummy data class, I wrote a mockup of how to access multi-leveled list or map variables.

The basic issue with your code is that you need to loop an additional time, to access the lists inside your list of lists. Multiple repeats using your list structure is demonstrated below.

The complex issue is that your data seems to be poorly organized, and could use optimization, which would in turn make your visualforce code simpler. Instead of the second list, maybe something such as Map<User, Map<String, Forecast>>, with the strings being the forecast stages?

Test Page

<apex:page controller="TestClass">
    <apex:pageBlock title="Nodes">
        <apex:repeat value="{!KeySet}" var="Key">
            <apex:repeat value="{!NodeMap[Key]}" var="listOfLists" >
                <apex:pageBlockTable value="{!listOfLists}" var="listOfNodes">
                        <apex:column value="{!Key}" headerValue="Key" />
                        <apex:column headerValue="Value">
                            <apex:repeat value="{!listOfNodes}" var="node">
                                <apex:outputText>{!node.Value}</apex:outputText>
                            </apex:repeat>
                        </apex:column>                  
                </apex:pageBlockTable>
            </apex:repeat>
        </apex:repeat>
    </apex:pageBlock>
</apex:page>

Test Class

public class TestClass {

    public Map<String, List<List<Node>>> NodeMap { get; set; }

    public TestClass() {
        NodeMap = new Map<String, List<List<Node>>>(); 

        NodeMap.put('First', new List<List<Node>>{
                new List<Node>{ new Node('Test'), new Node('Test2') },
                new List<Node>{ new Node('Test3'), new Node('Test4') }
        }); 

        NodeMap.put('Second', new List<List<Node>>{
                new List<Node>{ new Node('Test5'), new Node('Test6') },
                new List<Node>{ new Node('Test7'), new Node('Test8') }
        }); 
    }

    public List<String> KeySet {
        get {
            return new List<String>(NodeMap.keySet()); 
        }
    }

    public class Node {
        public Object Value { get; set; }

        public Node(Object Value) {
            this.Value = Value; 
        }
    }
}

Output

enter image description here