function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
B. Wade LovellB. Wade Lovell 

Error: Unknown Property "String.Services__c

I have the following very simple VF page to display two dependent picklists (3 tiers total) using a custom controller. When I attempt to save the VF page, I get the error message above.
In the developer console, I see two Problems at Line 0. 1) ABS_Services_Input, Unknown property 'String.Services__c and 2) "Duplicate value found: duplicates value on record with id:" (Yes, literally. No id # given.)

<apex:page controller="ABSServicesController">
    <apex:messages style="color:red"></apex:messages>  
    <apex:form >
        <apex:pageBlock title="Dependent Picklist Entry">
            <apex:repeat value="{!serviceList}" var="svcItem">
                <apex:pageBlockSection title="{!svcItem.Services__c}" columns="1">
                    <apex:pageBlockSection title="{!svcItem.Capabilities__c}" columns="1">
                        <apex:pageBlockSection title="{!svcItem.Sub_Capabilities__c}" columns="1">
                        </apex:pageBlockSection>
                    </apex:pageBlockSection>
                </apex:pageBlockSection>
            </apex:repeat>
        </apex:pageBlock>
    </apex:form>
</apex:page> 

This is my Custom Controller code:

public with sharing class ABCServicesController{

    public String serviceList { get; set; }
 
    public List<ServiceOffered__c> servicesList{get;set;}
    public Map<String, Map<String, List<String>>> serviceMap{get;set;}
    
    public ABCservicesController(){
        serviceMap = new Map<String, Map<String, List<String>>>();
        
        servicesList = [Select ID, Services__c, Capabilities__c, Sub_Capabilities__c From ServiceOffered__c];
        
        for(ServiceOffered__c svcItem : servicesList) {
            if(serviceMap.containsKey(svcItem.Services__c)) {
                if(serviceMap.get(svcItem.Services__c).containsKey(svcItem.Capabilities__c)) {
                    serviceMap.get(svcItem.Services__c).get(svcItem.Capabilities__c).add(svcItem.Sub_Capabilities__c);
                } else {                    
                    serviceMap.get(svcItem.Services__c).put(svcItem.Capabilities__c, new List<String>{svcItem.Sub_Capabilities__c});
                }
            } else {
                Map<String, List<String>> m = new Map<String, List<String>>();
                m.put(svcItem.Capabilities__c, new List<String>{svcItem.Sub_Capabilities__c});
                serviceMap.put(svcItem.Services__c, m);
                //new Map<String, List<String>>{svcItem.Capabilities__c : new List<String>{svcItem.Capabilities__c}}
            }
        }
    }     
}

I do not know if it is relevant but earlier I was getting an unknow property error serviceList related to the line "Public List<ServiceOffered__c> serviceList{get;set;}".  
My path toward resolution, besides asking all of you great folks, is to figure out why the variable svcItem was expected to be something other than a string when every service being pulled into the List is a string.
Thanks in advance,
Wade
Best Answer chosen by B. Wade Lovell
Glyn Anderson 3Glyn Anderson 3
In the VF page, the apex:repeat is iterating the collection "serviceList", which contains Strings.  So the var, "svcItem" is a String.  But you're trying to reference fields off of "svcItem":  "{!svcItem.Services__c}", "{!svcItem.Capabilities__c}", "{!svcItem.Sub_Capabilities__c}".  It appears you want "svcItem" to be a record of type ServiceOffered__c.  I notice two things in the controller:  "serviceList" is never initialized; and you're creating a list of ServiceOffered__c called, "servicesList".  Try changing the apex:repeat so that it iterates "servicesList" instead of "serviceList".  I also offer the refactoring below.  It's a technique I use to manage maps of collections that doesn't require all the "else" statements, and so it's easier to test.

<pre>
public with sharing class ABCServicesController
{
    public List<ServiceOffered__c> servicesList { get; set; }
    public Map<String, Map<String, List<String>>> serviceMap { get; set; }
    
    public ABCservicesController()
    {
        serviceMap = new Map<String, Map<String, List<String>>>();

        servicesList = [Select ID, Services__c, Capabilities__c, Sub_Capabilities__c From ServiceOffered__c];

        for ( ServiceOffered__c svcItem : servicesList )
        {
            if ( !serviceMap.containsKey( svcItem.Services__c ) )
            {
                serviceMap.put( svcItem.Services__c, new Map<String, List<String>>() );
            }
            Map<String, List<String>> capabilitiesMap = serviceMap.get( svcItem.Services__c );
            if ( !capabilitiesMap.containsKey( svcItem.Capabilities__c ) )
            {
                capabilitiesMap.put( svcItem.Capabilities__c, new List<String>() );
            }
            capabilitiesMap.get( svcItem.Capabilities__c ).add( svcItem.Sub_Capabilities__c );
        }
    }
}
</pre>

All Answers

Glyn Anderson 3Glyn Anderson 3
In the VF page, the apex:repeat is iterating the collection "serviceList", which contains Strings.  So the var, "svcItem" is a String.  But you're trying to reference fields off of "svcItem":  "{!svcItem.Services__c}", "{!svcItem.Capabilities__c}", "{!svcItem.Sub_Capabilities__c}".  It appears you want "svcItem" to be a record of type ServiceOffered__c.  I notice two things in the controller:  "serviceList" is never initialized; and you're creating a list of ServiceOffered__c called, "servicesList".  Try changing the apex:repeat so that it iterates "servicesList" instead of "serviceList".  I also offer the refactoring below.  It's a technique I use to manage maps of collections that doesn't require all the "else" statements, and so it's easier to test.

<pre>
public with sharing class ABCServicesController
{
    public List<ServiceOffered__c> servicesList { get; set; }
    public Map<String, Map<String, List<String>>> serviceMap { get; set; }
    
    public ABCservicesController()
    {
        serviceMap = new Map<String, Map<String, List<String>>>();

        servicesList = [Select ID, Services__c, Capabilities__c, Sub_Capabilities__c From ServiceOffered__c];

        for ( ServiceOffered__c svcItem : servicesList )
        {
            if ( !serviceMap.containsKey( svcItem.Services__c ) )
            {
                serviceMap.put( svcItem.Services__c, new Map<String, List<String>>() );
            }
            Map<String, List<String>> capabilitiesMap = serviceMap.get( svcItem.Services__c );
            if ( !capabilitiesMap.containsKey( svcItem.Capabilities__c ) )
            {
                capabilitiesMap.put( svcItem.Capabilities__c, new List<String>() );
            }
            capabilitiesMap.get( svcItem.Capabilities__c ).add( svcItem.Sub_Capabilities__c );
        }
    }
}
</pre>
This was selected as the best answer
B. Wade LovellB. Wade Lovell
Fantastic! Thank you for your support getting through this issue. I was showing this to a couple local SF developers and they also identified the typo on serviceList vs servicesList but you have taken this a lot further.I was definitely intending "svcItem" to be a record of type ServiceOffered__c.  I'll iterate on this and report back.
Glyn Anderson 3Glyn Anderson 3
Glad to have helped.  Please do me the favor of marking my post as the "solution".  Thanks!
B. Wade LovellB. Wade Lovell
Shoot, I thought I'd already done so :-)  Now it is the appropriate shade of green. Happy St. Patrick's Day! (Almost)