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?

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>
  • This works great, especially since it avoids a page error if the key doesn't exist. – MarsDev Aug 16 '16 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.

  • 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 '16 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.