Find your content:

Search form

You are here

Can't get "rendered" to work with checking a map for null

 
Share

I have been trying for a good few hours to only get my apex:outputLink to show up if it is a key within a map in my controller.

It keeps giving me the generic 'Syntax Error'.

Here's the VF:

<apex:repeat value="{!alphabet}" var="a">
        <apex:outputLink value="{!a}" rendered="{!IF({!cons}.get({!a}) == null, true, false)}">{!a}</apex:outputLink>                       
        &nbsp;|&nbsp;
</apex:repeat>

So "cons" is a Map>() that gets loaded in the constructor. "alphabet" is a simple List of Strings - "A", "B", "C" all the way to "Z".

Basically I would like to know if cons.get("A") == null, cons.get("B") == null, and only show the outputLink if this is not the case.

EDIT: I've tried with:

rendered="{!IF(!cons[a] != null, true, false)}"

which at least compiles, but gives me the error "Map key A not found in map"

EDIT2: I've made sure cons contains all the keys. So now I'm looking to see if the associated List size is greater than 0. However

<apex:outputLink value="{!a}" rendered="{!IF(cons[a].size!=0, true, false)}">{!a}</apex:outputLink>

gives the following: Incorrect parameter for subscript. Expected Number, received Text

EDIT3 - UPDATE FOR PETER

Controller:

public Map<String, ContactListViewController.ListWrapper> cons {get;set;}

private class ListWrapper{

    public List<Contact> theList {get;set;}

    public ListWrapper(){}

    public ListWrapper(List<Contact> theList){

        this.theList = theList; 
    }

    public Integer size {

        get {
            return theList.size();
        }
    }
}

VF:

<apex:repeat value="{!alphabet}" var="a">
                <apex:outputLink value="{!a}" rendered="{!IF(cons[a].size>0, true, false)}">{!a}</apex:outputLink>                      
                &nbsp;|&nbsp;
</apex:repeat>

This code is working fine.


Attribution to: George S.

Possible Suggestion/Solution #1

you can do the one below : public Map> accountsMap {get; set;}

Refer : http://bobbuzzard.blogspot.com/2011/03/visualforce-dynamic-map-bindings.html

LMK if this helped :)


Attribution to: Rao

Possible Suggestion/Solution #2

Cleaner version :

<apex:page controller="testconr" > 
<apex:form > 
<apex:repeat value="{!acc}" var="a"> 
<apex:outputLink value="{!a}" rendered="{!If(ISBLANK(cons[0]),true,false)}"> hai </apex:outputLink>
</apex:repeat> 
</apex:form>
</apex:page>

controller :

public with sharing class testconr {
public map<integer,string>cons{get;set;}
List<Account> acc = [select id,name from account limit 10];

public list<account> getAcc() {
cons = new map<integer,string>();
system.debug('ACC VALUE IS' + acc);
for( integer i=0;i<acc.size();i++){
cons.put(i,acc[i].name);
}
    return acc;
}

}

Attribution to: Rao

Possible Suggestion/Solution #3

It is not possible to check whether a Map in your controller has a key in it from your VF page in a dynamic fashion the way that you were trying. From your VF page, if you try to access a Map with a key that does not map to a value you will get an error. See the VF developers guide section on Lists and Maps for more information.

I see that you fixed that in EDIT 2, by making sure that all keys are in cons, so that solves that part.

Now you are getting the error: Incorrect parameter for subscript. Expected Number, received Text

<apex:outputLink value="{!a}" rendered="{!IF(cons[a].size!=0, true, false)}">{!a}</apex:outputLink>

I reproduced this error. I can access cons[a][0] and get the 0th element of each List in each Map entry and I can also just write out cons[a] without an issue. It is just an issue when trying to access size. I'm not totally sure why.

To get around your problem you could add an extra layer of indirection to wrap the list and get the size differently: Update: put the code inside of a class

public class ListWrapperController {
    public class ListWrapper {
        public ListWrapper(List<String> t) {
            theList = t;
        }
        public List<String> theList { get; set; }
        public Integer size { 
            get { 
                return theList.size(); 
            }
        }
    }

    public List<String> alphabet { 
        get { 
            return new List<String>{'a','b','c','d','e'}; 
        }
    }
    public Map<String, ListWrapper> cons { 
        get { 
            return new Map<String, ListWrapper>{
                'a'=>new ListWrapper(new List<String>()), 
                'b'=>new ListWrapper(new List<String>{'bbbb'}), 
                'c'=>new ListWrapper(new List<String>{'cccc'}), 
                'd'=>new ListWrapper(new List<String>{'dddd'}), 
                'e'=>new ListWrapper(new List<String>{'eeee'})
            }; 
        } 
    }
}

Then in the VF your call to size should work because it will be calling your wrapper class's size method (or whatever you name the method...doesn't have to be size) and not the actual Apex List's size method.

<apex:repeat value="{!alphabet}" var="a">
    <apex:outputLink value="{!a}" rendered="{!cons[a].size > 0}" >{!a}   </apex:outputLink>
</apex:repeat>

I tested that controller and that VF snippet and it ouptputted the following links (note no 'a' link since the ListWrapper that 'a' maps to has an empty list):

b c d e


Attribution to: Peter Knolle

Possible Suggestion/Solution #4

You're pretty close. In your first example at least, you had a few syntax type mistakes.

Example: rendered="{!IF({!cons}.get({!a}) == null, true, false)}" You have extra curly braces and exclamation marks around cons and a. Also, you cannot access the get method like that. In visualforce, you simply surround the key with square brackets like "cons[a]"

Also, rao is close as well, but he's only looking at the 0th element in the list instead of all the keys.

I've implemented a similar rolodex before, think it was using very similar if not nearly identical logic.

<apex:repeat var="letter" value="{!alphabetList}">
  <apex:outputLink value="{!letter}" rendered="{!NOT(ISBLANK(cons[letter]))}">{!letter}</apex:outputLink>
  <apex:outputText rendered="{!ISBLANK(cons[letter])}">{!letter}</apex:outputText>
  &nbsp;|&nbsp;
</apex:repeat>

The above Visualforce should output a link if a letter has records associated with it, else it will output the character without a link. You can also substitute commandLink for outputLink and link back to an action in your controller. Another option as well is to use the same link for all letters in the alphabet, but then use the apex:param child element under apex:outputLink to pass the letter of the alphabet with the link if that makes sense.


Attribution to: James Loghry
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/1510

My Block Status

My Block Content