17

is it possible to check for a specific key in a map i.e., whether it exists or not in VISUALFORCE page?

Based on this i need to render a pageblocktable.

3
  • Any reason why can't do this in controller? Commented Aug 21, 2013 at 13:54
  • actually my pageblocktable will be in apex:repeat and each time keyset of map would be different(I have other conditions in controller which populate the map with varying no.of keys). so i cant do this in controller
    – rani
    Commented Aug 21, 2013 at 14:04
  • See my answer on how I resolved this problem.
    – sfdcfox
    Commented Aug 21, 2013 at 14:12

5 Answers 5

10

No, there's no way to tell if a key exists or not. We don't have access to "containsKey", and any attempt to reference a key that doesn't exist will cause your code to crash and burn catastrophically.

Visualforce Error
Help for this Page

Map key 'value' not found in map
Error is in expression '{!not(isnull(keys[key]))}' in component <something> in page xyz

This is related to bug W-1065879 (according to an old forum post).

The solution is to check the key in Apex Code, and prevent the rendering of the element or component before the attempted access.

Here's an example used in live code:

public with sharing class orderCreateController {

    public Map<Id,Boolean> selectId { get; set; }
    public Map<Id,Quote> quoteList  { get; set; }

    // Irrelevant code redacted here

    // FIX FOR BUG W-1065879
    public wrapper[] getwrapperlist() {
        wrapper[] items = new wrapper[0];
        if(quotelist != null) {
            for(id quoteid:quotelist.keyset()) {
                items.add(new wrapper(this,quoteid));
            }
        }
        return items;
    }

    public class wrapper {
        public wrapper(orderCreateController c,id recordid) {
            con = c;
            id = recordid;
        }
        public boolean selected { get { return con.selectid.get(id); } set { con.selectid.put(id,value); } }
        public quote quote { get { return con.quotelist.get(id); } }

        private id id;
        private orderCreateController con;
    }
}

By iterating over {!wrapperlist}, we can create a pseudo-wrapper that will prevent non-existent keys from appearing.


EDIT

I just realized that this code takes some explaining. You can select from a list of quotes. The map may not always be populated with boolean values, so this wrapper class protects the Visualforce map controller from croaking.

7

You should really keep this type of logic out of a Visualforce page. A Visualforce page should be used simply for View logic. Instead, add it as part of your controller:

Apex

public Boolean getRenderPageBlockTable(){
    return mapToCheck.containsKey('keyToCheck');
}

Visualforce

<apex:pageBlockSection rendered="{!renderPageBlockTable}">
    ...
</apex:pageBlockSection>
1
  • 1
    But if that pageBlockSection is inside an apex:repeat, with a different 'keyToCheck' on each iteration, you have no way to pass the key back to the getRenderPageBlockTable to it can be checked. Herein lies the problem!
    – cyberspy
    Commented Dec 5, 2019 at 9:52
5

You can generate a delimited string with all the keys of the map in controller like this:

this.delimitedString = String.join(new List<String>(yourMap.keySet()), ',');

and then use the CONTAINS() formula function to check for the existence of that key in your Visualforce page.

<apex:outputText rendered="{!CONTAINS(delimitedString, key)}">
  {!yourMap[key]}
</apex:outputText>
3

Actually, you can build that natively on Visualforce Page, without any further variables. You need to use an apex:repeat, iterate over it, and inside the apex:repeat you may use an outputText (or similar and render the outputText just in case the iterated value matches your expected value. For example:

<apex:repeat value="{!yourMapVariable}" var="key"> <!--yourMapVariable is a map and you are not sure whether it contains or not the key 'Name' -->
     <apex:outputText rendered="{!key=='Name'}"> <!-- kind of containsKey(...) -->
         {!yourMapVariable[key]} <!-- this is now safe and will never produces an exception -->
     </apex:outputText>
</apex:repeat>
4
  • I would not recommend this approach. While it would work, it means you need to iterate over every single value in your list to find it. I would guess that this would be much slower to do than just running a .containsKey in Apex and returning that to your page through a controller. Commented Feb 28, 2014 at 14:23
  • the containsKey in Apex "iterates" also in order to find whether the key exists in the Map. I understand it's obviously an hack, but writing extra logic in Apex is not better either Commented Mar 3, 2014 at 13:59
  • Also it doesn't perform "much slower". Actually, I have never noticed any difference at all, but that might be kept in mind in case the pages becomes slow to load - or the collection is too huge for an apex:repeat (limit is 1000 AFAIK) Commented Mar 3, 2014 at 14:06
  • 1
    Unless SF has implemented something other than a traditional map, containsKey DOES NOT iterate each item! It generates a Hash Code to determine the memory offset of the item. You solution would be O^n while @JesseAltman solution is typically O(1). Data-Structures 101.
    – NSjonas
    Commented May 24, 2016 at 7:52
0

Instead of checking in VF page, I check in the code itself when you are populating the List/Map. I'm also using an of list items to display

personReferList is full list of apex:repeat.

   //creating a new List to hold the records which exists in map
   List<Person__c> PIList = new List<Person__c>();  
      //looping the list of records displayed in VF page                                
      for(Person__c pi: personReferList){
           //checking if all the records are in the Map
           if(mapPersonRef.containsKey(pi.Id)){
               //If yes, adding it to a new list. 
               PIList.add(pi);
           }
       }
  //clearing the original list first
  personReferList.clear();
  *//adding the from original list to the original list*
  personReferList.addAll(PIList);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .