Apex Component Controller returning Null for simple string value

apexcustom-controllerfieldsetsvisualforcevisualforce-component

TL;DR

Passing a simple string to component controller is returning null. I have already read this post but it didn't seem to imitate what I'm doing here. Pass value from apex component to controller

This article I just found. How do i pass data from visualforce page to component's custom controller? I'm trying to do this, but I don't need an output value, I need the value accessible within the Constructor of the component controller. Is this possible?

Goal

Greetings salesforce warriors!
I want to use fieldsets and pass in the api name of the fieldset into the functions of the component controller. This way I can reuse the components and modify the passin value to the name of fields that I want to use.

Problem w/ Code

When I attempt to passin a value from the ParentVFPage to the attribute passIn on the vf Component, the components controller is not receiving the value and only returning null.

VF Page (no controller)

I want to pass a string value from the page to the component.

<apex:page   lightningStylesheets="false" showHeader="false">
 
<div class="slds-p-around_x-small">
    <c:HB_BS_MenuItems />
    <div class="slds-p-around_x-small"></div>
   
    <c:HB_BS_Component
        passIn="HB_Card"/>
</div>

 

</apex:page>

VF Component

<apex:attribute type="string" name="passIn" assignTo="{!fieldNames}" description="field set name"></apex:attribute>

<apex:component controller="HB_BS_UserController" allowDML="true">
<div class="slds-card__body slds-card__body_inner">
                <apex:form id="ChangeUserDetails">
                    
                        
                            
                                <apex:commandButton styleClass="slds-button slds-button_brand" action="{!save}" value="Save"/>
                                <apex:commandButton styleClass="slds-button slds-button_outline-brand"  action="{!save}" value="Cancel"/>
                      
                    <apex:repeat value="{!fields}" var="f">
                        <div class="slds-form-element">
                            <label class="slds-form-element__label" for="text-input-id-53">{!f.label}</label>
                            <div class="slds-form-element__control slds-input-has-icon slds-input-has-icon_right">
                                <apex:inputField styleClass="slds-input" value="{!user[f.fieldPath]}"/>
                            </div>
                        </div>
                    </apex:repeat>
                    
                </apex:form>
            </div>
</apex:component>

Component Controller

 public with sharing class HB_BS_UserController {
    public User user {get;set;} 
    public String fieldNames; 
    public String getfieldNames(){
        return fieldNames;
    }
    public void setfieldNames(String s){
        fieldNames = s; 
    }

    public HB_BS_UserController() {
        System.debug(String.valueOf(this.getfieldNames()));
        this.user = getUser();
        
    }
    // User Fields 
    public List<Schema.FieldSetMember> getFields(){
        return SObjectType.User.FieldSets.HB_BS_UserAboutCard.getFields();
    }

    public  User  getUser(){
        String query = 'SELECT ';
        String userId = UserInfo.getUserId();  
        for(Schema.FieldSetMember f : this.getFields()){
            query += f.getFieldPath() + ', '; 
        }
        query += 'Id FROM User WHERE Id =: userId LIMIT 1'; 
        
        return Database.query(query);  
    }

    

    public void save(){
        update user; 
    }
}

Result

The fieldNames value returns null.

Best Answer

I'm surprised the VF page even compiled because you have ..

<apex:attribute type="string" name="passIn" assignTo="{!fieldNames}" description="field set name"></apex:attribute>

<apex:component controller="HB_BS_UserController" allowDML="true">
  ...

apex:attribute has to be a child of apex:component. You want:

<apex:component controller="HB_BS_UserController" allowDML="true">
  <apex:attribute type="string" name="passIn" assignTo="{!fieldNames}" description="field set name"></apex:attribute>
  ...
</apex:component>