0

Looking to get a little help with a custom controller and VF page for a Kanban we will use on our home screen. I have used the code from https://shrutisridharan.wordpress.com/2016/08/22/creating-a-kanban-view-for-leads/ and adjusted the code to display opportunities based on stages.

The error code i am getting is

Map key Pre-Renewal to be Sent not found in map Error is in expression '{!allOpps[stageName.value]}' in component in page oppkanbanvfp

which Line 79 of the VF page.

I have included the code below for the controller and VF page

Controller

public class OppKanbanCon {
    public static String OPP_MOVED = '{0} was moved successfully to {1}';

    public List<Schema.PicklistEntry> oppStageNames  { get; set; }
    public Map<String, List<Opportunity>> allOpps  { get; set; }

    public class UpdateStageName {
        public Boolean isSuccess;
        public String message;
    }

    public OppKanbanCon() {
        oppStageNames = Opportunity.StageName.getDescribe().getPicklistValues();
        fetchOpps();
    }

    @RemoteAction
    public static UpdateStageName updateOppStagename( Id oppId, String newOppStageName ) {
        Opportunity oppDetails = [
            SELECT  Id
                    ,Name
            FROM    Opportunity
            WHERE   Id = :oppId
        ];

        oppDetails.StageName = newOppStageName;
        UPDATE oppDetails;

        UpdateStageName updatedOppDetails = new UpdateStageName();
        updatedOppDetails.isSuccess    = true;
        updatedOppDetails.message      = String.format( OPP_MOVED, new List<String>{ oppDetails.Name, newOppStageName } );

        return updatedOppDetails;
    }

    private void fetchOpps() {
        List<Opportunity> opportunities = [
            SELECT  Id
                    ,Name
                    ,CloseDate
                    ,StageName
                    ,Income__c
            FROM    Opportunity WHERE recordTypeId = '0120V000001lDYyQAM' AND (StageName != 'Closed Won' AND StageName != 'Closed Lost')
        ];

        allOpps = new Map<String, List<Opportunity>>();

        for( Opportunity opportunity : opportunities ) {
            if( !allOpps.containsKey( opportunity.StageName ) ) {
                allOpps.put( opportunity.StageName, new List<Opportunity>{ opportunity } );
            }
            else {
                allOpps.get( opportunity.StageName ).add( opportunity );
            }
        }
    }
}

VF Page

<apex:page controller="OppKanbanCon" standardStylesheets="false" showHeader="false" applyHtmlTag="false" applyBodyTag="false" docType="html-5.0" cache="false" expires="0">
    <html>
        <head>
            <meta charset="utf-8" />
            <meta http-equiv="x-ua-compatible" content="ie=edge" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />

            <title>Lead Kanban</title>

            <apex:slds />
            <link type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />
            <link type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.css" rel="stylesheet" />

            <style type="text/css">
                body {
                    padding: 1em;
                }
                .slds-item {
                    box-shadow: 0 0 10px gray;
                    border: none !important;
                    background-color: #fff;
                    border-radius: 0 !important;
                    border-left: 5px solid #56aadf !important;
                }
                .slds-title {
                    border-radius: 3px;
                    background-color: #e0e5ee;
                    border: 1px solid #d8dde6;
                    cursor: move;
                }
                .slds-col {
                    height: 520px;
                    overflow-y: auto;
                    border-left: 1px solid whitesmoke;
                }
                .slds-item-placeholder {
                    border: 2px dotted gray !important;
                    height: 5rem;
                }
                .moving-card {
                    opacity: 0.5;
                    transform: rotate( -5deg );
                }
            </style>
        </head>
        <body>
            <div class="slds-scope">
                <!--Page Header-->
                <div class="slds-page-header slds-m-bottom--small" role="banner">
                    <div class="slds-media slds-media--center">
                        <div class="slds-media__body">
                            <p class="slds-page-header__title slds-truncate slds-align-middle slds-text-heading--large">
                                <strong><i class="fa fa-th" aria-hidden="true"></i>&nbsp;Lead Kanban</strong>
                            </p>
                            <p class="slds-text-body--small page-header__info">Adjusting Lead Stages have never become so easy!</p>
                        </div>
                    </div>
                </div>

                <!--Kanban Column Headers-->
                <div class="slds-grid">
                    <div class="slds-tabs--path" role="application">
                        <ul class="slds-tabs--path__nav" role="tablist">
                            <apex:repeat value="{!oppStageNames}" var="stageName">
                                <li class="slds-tabs--path__item slds-is-incomplete" role="presentation">
                                    <a class="slds-tabs--path__link" tabindex="-1" role="tab" href="javascript:void(0);">
                                        <span class="slds-tabs--path__title slds-text-heading--medium">{!stageName.label}</span>
                                    </a>
                                </li>
                            </apex:repeat>
                        </ul>
                    </div>
                </div>

                <!--Kanban Columns-->
                <div class="slds-grid">
                    <apex:repeat value="{!oppStageNames}" var="stageName">
                        <div class="slds-col slds-size--3-of-12 slds-has-dividers--around-space slds-scrollable--y" name="{!stageName.value}">
                            <apex:repeat value="{!allOpps[stageName.value]}" var="Opp">
                                <div class="slds-item slds-m-around--small" id="{!Opp.Id}">
                                    <div class="slds-tile slds-tile--board">
                                        <h3 class="slds-section-title--divider slds-m-bottom--small slds-title">
                                            <a href="javascript:void(0);">
                                                <i class="fa fa-user fa-fw" aria-hidden="true"></i>&nbsp;{!Opp.Name}
                                            </a>
                                        </h3>

                                        <div class="slds-tile__detail slds-text-body--small">
                                            <p class="slds-truncate">
                                                <i class="fa fa-briefcase fa-fw" aria-hidden="true"></i>&nbsp;{!Opp.CloseDate}
                                            </p>

                                            <p class="slds-truncate">
                                                <i class="fa fa-building fa-fw" aria-hidden="true"></i>&nbsp;{!Opp.Income__c}
                                            </p>

                                            <p class="slds-truncate">
                                                <i class="fa fa-envelope fa-fw" aria-hidden="true"></i>&nbsp;{!Opp.Email}
                                            </p>
                                        </div>
                                    </div>
                                </div>
                            </apex:repeat>
                        </div>
                    </apex:repeat>
                </div>
            </div>
            <script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>
            <script type="text/javascript" src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
            <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.js"></script>
            <script type="text/javascript">
                $( ".slds-col" ).sortable(
                    {
                        connectWith: ".slds-col",
                        handle: ".slds-title",
                        placeholder: "slds-item slds-m-around--small slds-item-placeholder",
                        start: function( event, ui ) {
                            $( ui.item ).addClass( "moving-card" );
                        },
                        stop: function( event, ui ) {
                            $( ui.item ).removeClass( "moving-card" );

                            var oppId             = $( ui.item ).attr( "id" );
                            var newOppStageName   = $( ui.item ).parent().attr( "name" );

                            OppKanbanCon.oppStageNames(
                                oppId,
                                newOppStageName,
                                function( result, event ) {
                                    if( result.isSuccess ) {
                                        toastr.info( result.message );
                                    }
                                }
                            );
                        }
                    }
                );
            </script>
        </body>
    </html>
</apex:page>

Any help would be very much appreciated.

Thanks!

0

You just don't have at least one Opportunity in each Stage, so some of the keys that you accumulate in oppStageNames don't exist in allOpps.

An easy fix would be to removethis code

        if( !allOpps.containsKey( opportunity.StageName ) ) {
            allOpps.put( opportunity.StageName, new List<Opportunity>{ opportunity } );
        }

where you lazy-add a child collection for each stage name found on an Opportunity, and instead iterate over oppStageNames prior to the Opportunity loop, adding a child collection for each stage name.

Then, your Visualforce page can rely on having at minimum an empty list corresponding to each Opportunity stage.

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.