+ Start a Discussion
TehNrdTehNrd 

apex:Param assignTo not working in a dataTable (bug)

There were a few times I thought I may have been literally losing my mind trying to isolate this issue but I was finally able to nail down the steps to reproduce (and solution). Sometimes the param value is not being assign to the variable in the controller.

Here is the code to reproduce. I tried to make it as short as possible but sorry it is still a little long, see steps below code:
Code:
Page:

<apex:page controller="paramBug" > <apex:form > <apex:pageBlock > <apex:outputPanel id="table"> {!showTable} <apex:pageBlockTable value="{!opps}" var="o" rendered="{!showTable}"> <apex:column headerValue="Status"> <apex:outputPanel id="oppStatus"> <apex:outputText value="Y" rendered="{!IF(o.status = 'modified', true, false)}"/> </apex:outputPanel> </apex:column> <apex:column value="{!o.opp.Name}"/> <apex:column > <apex:facet name="header"> <apex:commandLink value="Stage" rerender="table,debug" action="{!sortTable}" status="sorting"> <apex:param value="StageName" assignTo="{!sortColumn}" /> </apex:commandLink> </apex:facet> <apex:inputField value="{!o.opp.StageName}"> <apex:actionSupport event="onchange" action="{!change}" rerender="oppStatus,buttons"> <apex:param name="oid" value="{!o.opp.id}" assignTo="{!changedOpp}" /> </apex:actionSupport> </apex:inputField> </apex:column> </apex:pageBlockTable> </apex:outputPanel> </apex:pageBlock> </apex:form> </apex:page>

Controller:

public class paramBug {

List<oppWrapper> opps = new List<oppWrapper>();
List<SelectOption> stages;
public ID changedOpp {get; set;}
public string sortColumn {get; set;}
Map<String,String> sortOrder = new Map<String,String>();

//Constructor
public paramBug(){
for(Opportunity opp : [select Id, Name, StageName from Opportunity limit 10]){
opps.add(new oppWrapper(opp));
}
}

public List<oppWrapper> getOpps(){
return opps;
}

public void change(){
for(oppWrapper o : getOpps()){
if(o.opp.Id == changedOpp){
o.status = 'modified';
}
}
}

public Boolean getShowTable(){
Boolean show = true;
if(opps.size() == 0 ){
show = false;
}
return show;
}

public void sortTable(){
transient List<oppWrapper> sortedOpps = new List<oppWrapper>();
transient Map<String, List<oppWrapper>> stringMap = new Map<String, List<oppWrapper>>();

system.debug('--------------This is the debug line to watch--------------------');
system.debug('sColumn: ' + sortColumn);

if(sortColumn == 'StageName'){
for(oppWrapper o : getOpps()){
Object oField = o.opp.get(sortColumn);
String fieldValue = (String)oField;

if(stringMap.get(fieldValue) == null) {
stringMap.put(fieldValue, new List<oppWrapper>());
}
stringMap.get(fieldValue).add(o);
}

transient List<String> keys = new List<String>(stringMap.keySet());
keys.sort();

for(String key:keys){
sortedOpps.addAll(stringMap.get(key));
}

//reverse order
if(sortOrder.get(sortColumn) == 'asc'){
sortedOpps.clear();
for(Integer i = (keys.size()-1);i >= 0; i--) {
sortedOpps.addAll(stringMap.get(keys.get(i)));
}
}

if(sortOrder.get(sortColumn) == 'asc'){
sortOrder.put(sortColumn,'desc');
}else{
sortOrder.put(sortColumn,'asc');
}

}
system.debug('sortedOpps: ' + sortedOpps);
system.debug('Opps: ' + Opps);
opps = sortedOpps;
}

public class oppWrapper{

public Opportunity opp {get; set;}
public String status {get; set;}

//Contructor
public oppWrapper(Opportunity opp){
this.opp = opp;
}
}
}

First let's show it working correctly:
1) Open up this page and open the System Log.
2) Click the Stage Name header. This passes a param to the variable "sortColumn" in the controller and calls the action method sortTable().
3) Monitoring the debug log you can see that this is correctly being passed over: line 41, column 9: sColumn: StageName

Now let's show it not working:
1) Reload the page.
2) Change the Stage of the first opp in the table. This runs the change() method in the controller and rerenders the contents of the Status column. A 'Y' should appear in the row of the edited opp.
3) Click the Stage header to sort. The table will disappear because the sort logic did not execute. If you look at the system log you can see that the param was not passed to the controller and sortColumn is null: line 41, column 9: sColumn: null

Now the fix. I don't know why or how this fixes it but it does. Simply adding the name attribute to the param component does the trick. It doesn't even matter what the name is, just as long as it is there:

Code:
Change this:
<apex:param value="StageName" assignTo="{!sortColumn}" />

to this:
<apex:param name="asdfasd" value="StageName" assignTo="{!sortColumn}" />

and it works.

So there you go. I'm pretty sure this is a bug but if it's not I'll modify the title.

-Jason




Message Edited by TehNrd on 01-16-2009 12:04 PM
wesnoltewesnolte

I had the same issue, and so did one other developer I work with. Unfortunately I've only come across your post now.. and could've saved myself alot of frustration if I'd found it earlier.

 

I feel your pain buddy.

Message Edited by wesnolte on 03-12-2009 02:43 AM
TehNrdTehNrd

My bad really as I didn't submit a case for this (I know I know thats bad) but I have to manage my workload and this fell off the the priority list once I found the work around. Usually the SF people are really good about tracking bugs on this board but they never commented on this one.

 

If you reached out to salesforce.com support point them here and report back if they submit a bug.

d3developerd3developer

Just had the same problem in an apex : repeat.

 

Thanks a ton for posting the solution. Couldn't find it documented anywhere else.

kdmrkdmr

Hi,

I am still facing this problem, the paramater value returns null in the postback, this actually happens when trying to create a dependent lookup. I had included the name option but still it does not stay, I keep loosing it when ever a postback happens. Is there any other way I can ensure that the value does not return null on postback.

Thanks

KD 

Ron WildRon Wild

Thank you, thank you, thank you!   You just put an end to my suffering ;-)

 

Ron

sai_lavusai_lavu
Saved me trouble too...thank you TehNrd!!
sfdcfoxsfdcfox

I just posted about this myself over the weekend. I was certain I was losing my sanity as well as my mind when I saw this behavior going on. I'm going to log in and test this out right now...

 

Edit: Nope. My "bug" still exists even with this workaround. For some reason, the order of (expected) operations in my controller isn't working, and I'm going to end up hurting myself if I think about it too much. Basically, assignTo does not call the setter method immediately, or at least not in time for the getter method for the data list to see that there are any results, which cumulates in the thing not working the way I'd like it. The logic astounds me...

Message Edited by sfdcfox on 07-20-2009 04:07 AM
DerGrobeDerGrobe

Did you find any solution for this kind of "timing" problem? I'm facing the very same problem and don't know how to solve it finally.

 

TIA

wootwoot

Hero!!!!!!!!!!!!!!!!!!!!!!  Thank you!!!!!!!!!!!!!!!!!!!!