0

I'm fairly new to developing on the Salesforce platform and I'm running into a bit of a problem. I have an Apex class with a map of Opportunity Stages and total values, and I'm trying to render a list item only if that map contains the related key - however I'm getting "Unknown function keyExists" error on the Visualforce page.

Apex Class:

Public Map<string,decimal> rawMap{get;set;}
public boolean keyExists(String checkKey) {
    return rawMap.containsKey(checkKey);
}

Visualforce Attempt 1:

<apex:outputPanel rendered="{!keyExists('Closed Lost')}">
            <-- Some Text -->
</apex:outputPanel>

Visualforce Attempt 2:

<apex:form>
    <apex:actionFunction action="{!keyExists}"  name="test">
        <apex:param value="Closed Lost" />
    </apex:actionFunction>
</apex:form>

Is there something obvious I'm missing? Or any ideas on how I can get around this?

UPDATE: I found a messy solution...

  1. Put the Map into a Javascript string variable on the Visualforce page.
  2. Create a Javascript method that checks the strings contents and sets a hidden div to contain the output boolean.
  3. Set your <apex:outputPanel> to render on that hidden components value

Apex Class:

Public Map<string,decimal> rawMap{get;set;}

Visualforce:

<script type='text/javascript'>
    var rawMap = '{!rawMap}';

    /* Checks if map contains a certain Opportunity Stage */
    function containsKey(findKey) {
        document.getElementById('containsKeyVar').innerHTML = rawMap.includes(findKey);
    }
</script>

<!-- This element is being used as a global variable: does Opportunity map contain  -->
<div id="containsKeyVar" style="display: none;">false</div>

<!-- Check if Stage Exists, and only then render -->
<script type="text/javascript">
    containsKey('Closed Lost');
</script>

<apex:outputPanel rendered="{!$Component.containsKeyVar}">
    <!-- Some Text -->
</apex:outputPanel>

Anyone have a better solution?

3 Answers 3

1

You can iterate through map keys and rerender section if particular key is specified:

public with sharing class MyController {
    Public Map<string,decimal> rawMap{get;set;}
    public MyController() {
        rawMap = new Map<string,decimal>();
        rawMap.put('Closed Lost', 11.1); 
    }
}

<apex:page controller="MyController" tabStyle="Account">
    <apex:form >
        <apex:pageBlock title="My Content"> 
            <apex:repeat value="{!rawMap}" var="dirKey">
                <apex:outputPanel rendered="{!dirKey=='Closed Lost'}">
                        <apex:outputText value="Closed Lost" />
                </apex:outputPanel>
                <apex:outputPanel rendered="{!dirKey=='Closed Won'}">
                    <apex:outputText value="Closed Won" />
                </apex:outputPanel>
            </apex:repeat>
        </apex:pageBlock> 
    </apex:form>
</apex:page>
1
  • This works great, especially since it avoids a page error if the key doesn't exist.
    – MarsDev
    Aug 16, 2016 at 17:49
1

So visualforce is one-way. You can't pass Params from the vf function call to the controller. In other words {!keyExists(foo)} throws the unknown function error because the method definition in the controller accepts a parameter, and when visualforce goes to invoke the method it's sending it without the parameter. (KeyExists() vs. keyExists(foo))

A better way of doing this is to use a wrapper object. In fact, I like to only expose a wrapper object via the controller to page. Your wrapper object can be setup to have a list variable that contains a wrapper of opportunity objects that explicitly set a property for rendered or not.

This has a number of advantages, from ease-of-testing to making your markup easier to understand.

I would essentially do this:

Public class wrapper {

List opportunities = new List() }

And

Public Class OpportunityWrapper {

Public Boolean rendered }

Then in your VF page, you can simply iterate over wrapper.opportunities in a repeat tag using the panel's rendered tag set simply to the local iteration's rendered property.

1
  • Thank you, in my case, I'll have a wrapper with a list of lists [OpportunityStageName, Sum(Amount)] and repeat on it.
    – MarsDev
    Aug 16, 2016 at 17:23
0

You can not call the controller method keyExists from the VisualForce page, however, you can access the rawMap using Dynamic Visualforce Bindings, specifically for Apex Maps

<apex:outputPanel rendered="{!NOT(ISBLANK(rawMap['Closed Lost']))}">
  <!-- Some Text -->
</apex:outputPanel>

NOTE: If there isn’t a value mapped to a particular key, the Visualforce page returns an error message.

You must log in to answer this question.

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