You need to sign in to do that
Don't have an account?
SteveEthos
The timing of passing in Attribute data to a Controller of a Component is not working properly.
We have a VF page that uses multiple instances of a custom component, when we pass information in through the Component attributes, and try to get them to the Component Controller, they are not setting before a apex:dataTable reads from the controller.
Example:
----------------------------
Page has this code: (this segment is inside of a PageBlockSection)
<tr>
<td><c:MedComp cnId="{!cn__c.id}" medGrp="ACONV"/></td>
<td><c:MedComp cnId="{!cn__c.id}" medGrp="STIM"/></td>
</tr>
<td><c:MedComp cnId="{!cn__c.id}" medGrp="ACONV"/></td>
<td><c:MedComp cnId="{!cn__c.id}" medGrp="STIM"/></td>
</tr>
----------------------------
Component has this code:
<apex:component controller="MedCompController">
<apex:attribute name="cnId" type="String" required="true" description="Cn ID" assignTo="{!cnID}"></apex:attribute>
<apex:attribute name="medGrp" type="String" required="true" description="Med Group" assignTo="{!medGrp}"></apex:attribute>
<apex:dataTable value="{!meds}" var="med">
<apex:column >
<apex:facet name="header">Trade Name</apex:facet>
<span style="{!med.tradeStyle}">{!med.tradeName}</span>
</apex:column>
<apex:column >
<apex:facet name="header">Generic Name</apex:facet>
<span style="{!med.genericStyle}">{!med.genericName}</span>
</apex:column>
<apex:column >
<apex:facet name="header">Sensitivity</apex:facet>
<span style="{!med.sensitivityStyle}">{!med.sensitivity}</span>
</apex:column>
</apex:dataTable>
</apex:component>
<apex:attribute name="cnId" type="String" required="true" description="Cn ID" assignTo="{!cnID}"></apex:attribute>
<apex:attribute name="medGrp" type="String" required="true" description="Med Group" assignTo="{!medGrp}"></apex:attribute>
<apex:dataTable value="{!meds}" var="med">
<apex:column >
<apex:facet name="header">Trade Name</apex:facet>
<span style="{!med.tradeStyle}">{!med.tradeName}</span>
</apex:column>
<apex:column >
<apex:facet name="header">Generic Name</apex:facet>
<span style="{!med.genericStyle}">{!med.genericName}</span>
</apex:column>
<apex:column >
<apex:facet name="header">Sensitivity</apex:facet>
<span style="{!med.sensitivityStyle}">{!med.sensitivity}</span>
</apex:column>
</apex:dataTable>
</apex:component>
----------------------------
Component Controller has this code:
public class MedCompController
{
List<MedSensitivity> meds;
private String cnId;
private String medGrp;
public void setCnId(String s)
{
cnId = s;
}
public String getCnId()
{
return cnId;
}
public void setMedGrp(String s)
{
medGrp = s;
}
public String getMedGrp()
{
return medGrp;
}
public List<MedSensitivity> getMeds()
{
if (meds == null )
{
meds = new List<MedSensitivity>();
for(med__c medRow : [select trade__c, generic__c, sensitivity__c, sub_group_name__c, sub_group_sensitivity__c
from med__c
where
drug_class__c = :medGrp AND cn_id__c = :cnId])
{
MedSensitivity medItem = new MedSensitivity();
medItem.Setup( medRow);
meds.Add( medItem);
}
}
return meds;
}
}
{
List<MedSensitivity> meds;
private String cnId;
private String medGrp;
public void setCnId(String s)
{
cnId = s;
}
public String getCnId()
{
return cnId;
}
public void setMedGrp(String s)
{
medGrp = s;
}
public String getMedGrp()
{
return medGrp;
}
public List<MedSensitivity> getMeds()
{
if (meds == null )
{
meds = new List<MedSensitivity>();
for(med__c medRow : [select trade__c, generic__c, sensitivity__c, sub_group_name__c, sub_group_sensitivity__c
from med__c
where
drug_class__c = :medGrp AND cn_id__c = :cnId])
{
MedSensitivity medItem = new MedSensitivity();
medItem.Setup( medRow);
meds.Add( medItem);
}
}
return meds;
}
}
---------------------------------------------------------------
The CnID and Med groups are passed into the Component through the Attributes at the top of the component. We have set the {assignTo} attributes, so they should call the Setter methods on the Controller, and the values should be stored on the Component.
The problem is that it appears as though the apex:dataTable is accessing the {meds} attribute on the Controller prior to the setter values from the attributes being set.
How can we pass data into the Component Controller from the calling page, and have it availble for the building of the Data table? There appears to be no way for this to work.
All the examples for the SQL in the Controller show using the Current Page parameters. However, we will have mutliple instances of the Components on a page, and need to send different values to each one.
This appears to be a bug in Visual Force.
Thanks,
Steve
I have opened a bug for myself to track this one - I will verify that this has been fixed in the next release and let you know.
Message Edited by dchasman on 08-01-2008 03:28 PM
Do you have any workarounds?
I have 4 instances of the Component on the same page. We need to send different values to each one.
I considered adding parameters to the page, and reading them inside of the Component. However, all of the Component instances will read the same values, so that does not work.
The problem is the timing with the dataTable, it reads the value and tries to run the SQL before I can find a way to get some populated attribtues to it.
Are there any ways to pass values into the Component Controller before the dataTable starts its initialization? I have to set 2 different values in the SQL when it runs.
It seemed as though the Attributes were the best way to get values into the Component and to the Controller. Are there any other ways?
Thanks,
Steve
public List<MedSensitivityDisp> getMedSenBB()
{
return getMedSensitivities('BB');
}
public List<MedSensitivityDisp> getMedSenACONV()
{
return getMedSensitivities('ACONV');
}
public List<MedSensitivityDisp> getMedSenADEP()
{
return getMedSensitivities('ADEP');
}
public List<MedSensitivityDisp> getMedSenSTIM()
{
return getMedSensitivities('STIM');
}
private List<MedSensitivityDisp> getMedSensitivities(String drugClass)
{
List<MedSensitivityDisp> returnList = new List<MedSensitivityDisp>();
for(med__c medRow : [select trade__c, generic__c, sensitivity__c from med__c where drug_class__c = :drugClass AND cnid__c = :cn.id])
{
MedSensitivityDisp medItem = new MedSensitivityDisp();
medItem.Setup( medRow);
returnList.Add( medItem);
}
return returnList;
}
<td><c:MedComp medList="{!medSenBB}"/></td>
<td><c:MedComp medList="{!medSenADEP}"/></td>
</tr>
<tr>
<td><c:MedComp medList="{!medSenACONV}"/></td>
<td><c:MedComp medList="{!medSenSTIM}"/></td>
</tr>
<apex:component controller="MedCompController">
<apex:attribute name="medList" type="MedSensitivityDisp[]" required="true" description="data list"></apex:attribute>
<apex:dataTable value="{!medList}" var="med">
<apex:column >
<apex:facet name="header">Trade Name</apex:facet>
<span style="{!med.tradeStyle}">{!med.tradeName}</span>
</apex:column>
<apex:column >
<apex:facet name="header">Generic Name</apex:facet>
<span style="{!med.genericStyle}">{!med.genericName}</span>
</apex:column>
<apex:column >
<apex:facet name="header">Sensitivity</apex:facet>
<span style="{!med.sensitivityStyle}">{!med.sensitivity}</span>
</apex:column>
</apex:dataTable>
</apex:component>
****************************************************************
Excellent.
Other than this issue, I have been happy with how the Component architecture is setup. I like the ability to break up the logic into reusable sections that encapsulate all of their logic. The Attributes will allow for the passing in of the necessary data.
I am looking forward to the new release!
Thanks,
Steve
I am facing a similar issue, where my controller requires value to be passes in the page thru the Custom Component. The data on the VF page when it load is null because the page renders before the data is retrieved from the sql. You solution might work for me as well, but I do not understand how you pass the "cn" parameter below. Is it thru the 'assignTo' attribute from the component. How to you pass that parameter?
for(med__c medRow : [select trade__c, generic__c, sensitivity__c from med__c where drug_class__c = :drugClass AND cnid__c = :cn.id])
Thanks in advance.
-Ramya
The SObject cn is loaded in the Controller for the page that contains the Component. It is loaded and then the data is passed into the Component from there.
The key to this is that all of the data necessary is passed in directly, instead of having the Component load it itself.
Hopefully this will no longer be needed in the next release.
Good Luck,
Steve