0

Extend question from here

Below code step 1 i have tried with rendering component1 and component2 it is working fine.

step 1:

Visualforce Component1

 <apex:component>
    <div>
       <h1>Component 1 </h1>
    </div>
    </apex:component>

Visualforce Component2

 <apex:component>
    <div>
       <h1>Component 2 </h1>
    </div>
    </apex:component>

Visualforce page

 <apex:page controller="compcntr2" >
     <apex:dynamicComponent componentValue="{!comp1}"/>        
     <apex:dynamicComponent componentValue="{!comp2}"/>        
    </apex:page>

Controller:compcntr2

public class compcntr2 {
    public Component.c.component1 getComp1(){
    Component.c.component1 myCom = new Component.c.component1(); 
        return myCom;
        }

       public Component.c.component2 getComp2(){
        Component.c.component2 myCom = new Component.c.component2(); 
        return myCom;
        }
}

output image Below : Header value component 1 and component 2 is displayed.

enter image description here

But the problem is i am facing at Step 2.

Step 2:

Problem is when i try to render same component twice in the same page its not render twice , instead only once it will render. below i have change the visual force page only.

Visualforce page

   <apex:page controller="compcntr2" >
     <apex:dynamicComponent componentValue="{!comp1}"/>

     <apex:dynamicComponent componentValue="{!comp1}"/>

</apex:page>

output image Below :Header value component 1 displayed.

enter image description here

Step 3:

if i extend my question more why i am doing this is because i have planned of generating dynamic component using custom setting. Above code is i add added for understanding what is the problem. actually my code is as follows

Referring this code I have create my below code.

controller

I get two component Name ie.. component1 and component2 from custom setting and assign into comp Map.

   public class comcntr {  
        public list<String> menuList{get;set;}
        public integer componentSize{get;set;}

        public comcntr() {
            Map<String, MyPackagePrefix__componentList__c> comp = MyPackagePrefix__componentList__c.getAll();   
            menuList=new list<string>(comp.keySet());        
            system.debug('compName ********' + menuList);  //working 
            componentSize=0;
        }

        public ApexPages.Component getCustomComponent() {
            system.debug('componentName__c ********' + menuList[componentSize]);
            MyPackagePrefix__componentList__c comp;
            if(componentSize==0){
             comp=  MyPackagePrefix__componentList__c.getValues(menuList[0]); 
                system.debug('inside 1 ');
            }
            else {
             comp=  MyPackagePrefix__componentList__c.getValues(menuList[1]);
                system.debug('inside 2 ');
            }
            componentSize=1;        
            system.debug('componentName__c ********' + comp.MyPackagePrefix__componentName__c);        
            Type reflector = Type.forName(comp.MyPackagePrefix__componentName__c);
            IComponentProvider provider = (IComponentProvider)reflector.newInstance();
            return provider.provideComponent();
        }       
    }

visualforce Page

<apex:page  controller="comcntr">
    <apex:repeat value="{!menuList}" var="component">               
           <apex:dynamicComponent componentValue="{!customComponent}"/>  
    </apex:repeat>

</apex:page>

i am getting all the value properly, but problem is dynamiceComponent is inside the repeat tag also , Dynamic component never calls customComponent second time. When i check the log file there no trace of second time execution call but still component 1 displayed twice.

Above code display component1 twice, instead of displaying component 1 and component 2.

enter image description here

Can anyone help me why this is happening .

  • 1
    This is just an aside, but we faced the same issue when using dynamic components in a repeat and were not able to find a workaround so we had to re-architect the solution to use hardcoded components. – dsharrison Oct 13 '17 at 16:29
  • @rahul-sharma any help i can get from you? – NITHESH K Oct 16 '17 at 13:10
1

Getter method used in "componentValue" for generating the dynamic component, is pretty much the culprit. As per behavior noticed, getter method is called only once irrespective of the number of times it is referenced in VF page. Seems to be a cache, though I do not see any documentation that guarantees the behavior. You can check the behavior by adding debug to the getter method. It shows up just once is debug log, irrespective that it is being used inside apex:repeat or number of times it is referenced.

For Step 2, is a known issue as per the Salesforce Success community. https://success.salesforce.com/issues_view?id=a1p30000000Rj1hAAC. However, there exists a suggested workaround that can suffice as a solution to the problem at this point of time i.e having separate getters for each component rendered. You can report that it affects you.

Apex class

public ApexPages.Component getDynamicComponent(){

    return new Component.DynamicComponent();
 }

public ApexPages.Component getDynamicComponent2(){

    return new Component.DynamicComponent();
}

VF page

<apex:dynamicComponent componentValue="{!dynamicComponent}" /> 
<apex:dynamicComponent componentValue="{!dynamicComponent2}" />

For Step 3, along with Step 2 workaround, provided that you already know the component names in advance (which pretty much you would know). Instead of using apex for checking which component to refer, we can do that on VF side using rendered property. This way you will end up having multiple getter methods which I have mentioned in the answer earlier and call them from VF separately.

Something like below in addition to the above code of separate getter,

<apex:repeat value="{!menuList}" var="component" >         

    <apex:outputPanel rendered="{!LOWER(component) == 'dynamiccomponent'}">
        <apex:dynamicComponent componentValue="{!dynamicComponent}" />
    </apex:outputPanel>
    <br/>
    <apex:outputPanel rendered="{!LOWER(component) == 'dynamiccomponent2'}">
        <apex:dynamicComponent componentValue="{!dynamicComponent2}" />
    </apex:outputPanel>

</apex:repeat>

c:componentName can(suggested) be used instead of apex:dynamiccomponent.

  • I don't know the component name, I will get the component names from custom setting. Step 1 and step2 snippet for understanding, step 3 is the real problem what i facing issue. If i could have know the component name already i should be displaying <c:componentName /> tag directly. – NITHESH K Oct 16 '17 at 9:17
  • Getter is the thing that holds us from achieving it. I've Edited to include this last point in your comment above. I understand that the sequence and components to be rendered you shall get from custom setting, still the component name would be something we know even when we enter record to the custom setting, I assume. – Sikha Baid Oct 16 '17 at 9:22
  • sikha-baid yes correct, But in vf page alreay you mentioned "dynamiccomponent2" at this point. i have to know component the component name first only. – NITHESH K Oct 16 '17 at 9:34
  • Do you have any specific number of components that has to be displayed? I expect a No on this. But if this is the case, you can play around with index in the apex:repeat. The summary/workaround is that, you need to have multiple getter methods. – Sikha Baid Oct 16 '17 at 9:43
  • Not specific component, component is keep on get added based on project requirement. and component name we have to mention in custom setting. if observe my sep 3 i am getting component name from custom setting. its unknown, can be increase or can be decrease. – NITHESH K Oct 16 '17 at 9:46

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.