function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
tobibeertobibeer 

Determine size of a list in a map in Visualforce

I have a map of this structure...

 

private Map<String,List<MyObject__c>> mymap = new Map<String,List<MyObject__c>>();

In order to keep things generic, it is not clear at all, how many string->list pairs there are going to be in the map. Now, if I repeat over one of these lists in a VisualForce page like this...

 

<apex:repeat value="{!mymap['someindex']}" var="el">
</apex:repeat>

 ...how am I going to determine the actual size of mymap['someindex']? Eventually I want to do something as simple as this...

 

<li class="{!IF(count=mymap['someindex'].size,'active','')}">

However, the size method of a list does not seem to work in VisualForce. Anyways, this procedure already seems to require for me to wrap this stuff with a quite redundant count variable like so...

 

<apex:variable var="count" value="{!0}"/>
<apex:repeat value="{!mymap['someindex']}" var="el">
    <apex:variable var="count" value="{!count + 1}"/>
    <li class="{!IF(count=mymap['someindex'].size,'active','')}">
</apex:repeat>

So, how would you do this, because my current solution looks like this and is far from generic at all and - as for my tastes - does not look good at all...

 

<apex:repeat value="{!mymap['myindex']}" var="el">
    <li class="{!IF(el.Property__c=='knownPropertyOfLastElementInList','last','')}">
        ...
    </li>
</apex:repeat>

...or is there a way to declare a getter in my controller that can receive parameters, somewhat like this...

 

<li class="{!IF(count=listlength('mymap','someindex'),'active','')}">

Cheers, Tobias.

Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox

You need a wrapper class for this:

 

 

public class controller {
  // ... some code here ...

private Map<String,myobject_list_wrapper> mymap = new map<string,myobject_list_wrapper>();
public class myobject_list_wrapper { public myobject_list_wrapper() { records = new list<myobject__c>(); } public list<myobject__c> records { get; set; } public integer getlastitem() { return records[records.size()-1]; } } // .. some other code here ... }

 

At this point, you should be able to do something like this:

 

 

<apex:repeat value="{!mymap['someindex'].records} var="el">
  <li class="{!if(el.id=mymap['someindex'].lastitem,'active','')}">
  </li>
</apex:repeat>

This should work with the advent of Dynamic Visualforce, assuming I have my syntax correct. A wrapper class is almost certainly necessary.

 

The other alternative would be:

 

 

public class controller {
  private map<string,list<myobject_wrapper>> mymap = new map<string,list<myobject_wrapper>>();
  public class myobject_wrapper {
    public myobject__c record { get; set; }
    public boolean isActive { get; set; }
  }
}

 

This one leaves your code alone, and you don't even have use the funky code anymore, just:

 

 

 

<li class="{!if(el.isactive,'active','')}">

There's definitely ways to get where you want ot be. Just think encapsulation, and you'll be fine.

 

All Answers

sfdcfoxsfdcfox

You need a wrapper class for this:

 

 

public class controller {
  // ... some code here ...

private Map<String,myobject_list_wrapper> mymap = new map<string,myobject_list_wrapper>();
public class myobject_list_wrapper { public myobject_list_wrapper() { records = new list<myobject__c>(); } public list<myobject__c> records { get; set; } public integer getlastitem() { return records[records.size()-1]; } } // .. some other code here ... }

 

At this point, you should be able to do something like this:

 

 

<apex:repeat value="{!mymap['someindex'].records} var="el">
  <li class="{!if(el.id=mymap['someindex'].lastitem,'active','')}">
  </li>
</apex:repeat>

This should work with the advent of Dynamic Visualforce, assuming I have my syntax correct. A wrapper class is almost certainly necessary.

 

The other alternative would be:

 

 

public class controller {
  private map<string,list<myobject_wrapper>> mymap = new map<string,list<myobject_wrapper>>();
  public class myobject_wrapper {
    public myobject__c record { get; set; }
    public boolean isActive { get; set; }
  }
}

 

This one leaves your code alone, and you don't even have use the funky code anymore, just:

 

 

 

<li class="{!if(el.isactive,'active','')}">

There's definitely ways to get where you want ot be. Just think encapsulation, and you'll be fine.

 

This was selected as the best answer
Mitesh SuraMitesh Sura

sfdcfox,

 

I have a similar issue. 

How can I use {!myMap.values} in VF page to iterate over the list returned by values() ? I can use values() in APEX, but not in VF page. 

Same goes for {!myMap.size}.


regards
ISVForce Partner

sfdcfoxsfdcfox

AFAIK, you can't access Map.size() nor Map.values() directly. You can, however, do the following:

 

// IN CONTROLLER
public map< string, string > myMap { get; set; }
public integer myMapSize { get { return myMap.size( ); } }

 

<!-- in page -->
myMap has {!myMapSize} elements.
<apex:dataTable value="{!myMap}" var="myMapKey">
  <apex:column value="Given {!myMapKey}, the value is {!myMap[myMapKey]}"/>
</apex:dataTable>

 

Mitesh SuraMitesh Sura

This helped in getting the map size and iterating it in VF page. 

 

thank you.

Karel SlabyKarel Slaby

 

Hey sfdcfox, I have another problem with wrapper class in map described here . Can you take a look on this? Thank you.

Karel.

Yakov VeromeevYakov Veromeev
Hi, tobibeer!
I know, your problem is solved six years ago, but I have something to add to your topic.
I faced with the same problem, but my colleague said that creating a wrapper class only for field is wrong solution. She offered another solution I found best for this case.

My controller:
public class myController {
    public static Map<MyObj1__c, List<MyObj2__c>> supermap {
        get { /* some awesome code here */ }
    }
}
The solution is to create a variable in VF page and call size property on it
<apex:repeat value="{!supermap}" var="currentObj1">
            <apex:variable var="currentList" value="{!supermap[currentObj1]}"/>
            <p>Look! I found this list contains {!currentList.size} item(s)!</p>
</apex:repeat>