• DerGrobe
  • NEWBIE
  • 0 Points
  • Member since 2009

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 2
    Questions
  • 5
    Replies

I have a VF page that uses an apex:repeat block with inputFields and actionSupport. If the action is fired the data is transmitted to the controller. So from that point of view everything is fine.

 

However I'd like to do some work in the setter, checking if some special fields are changed in fact.

 

See this very simple example that illustrates the problem

 

public with sharing class Testing {

public List<Account> values
{
get
{
System.debug('GETTER' + this.values);
return this.values;
}

set
{

System.debug('SETTER' + value);

// never get to this point!!!
this.values = value;
}
}

public String inputValue { get; set; }
public String outputValue { get; set; }

public Testing()
{
System.debug('Start Testing class');
/*
values = new List<String>();
values.add('One');
values.add('Two');
values.add('Three');
*/
values = [Select Id, Name from Account limit 3];
}

public PageReference dblClickAction()
{
System.debug('dblClickAction(): inputValue -> ' + inputValue);
System.debug('dblClickAction(): outputValue -> ' + outputValue);
System.debug('dblClickAction(): values -> ' + values);

//inputValue = outputValue;
return null;
}

}

 

And this is my VF page

 

 

<apex:page controller="Testing">
<apex:form >
<apex:pageBlock id="pBlock">
<apex:repeat value="{!values}" var="val">
<apex:outputText value="{!val.Name}" />
<apex:actionRegion >
<apex:inputText value="{!val.Name}">
<apex:actionSupport action="{!dblClickAction}" rerender="pBlock" event="onchange">
<apex:param assignTo="{!inputValue}" name="inputValue" value="{!val.Name}" />
</apex:actionSupport>
</apex:inputText>
<br />
</apex:actionRegion>
</apex:repeat>
</apex:pageBlock>
</apex:form>
</apex:page>

 

 

 

 What happens is that the getter of 'values' is called and the 'onchange' event fires perfectly. The rerender renders the new value of the field in the 'outputText'. Fine, BUT the setter of 'values' is never called and I'd like to do some comparison of the record returned with the actual one before setting the new one.

 

So I have no clue HOW the value is set in fact.

 

TIA

 

DerGrobe

 

hi all,

 

i have a problem with a custom setter method not being called for a custom object on a VF page.

 

Controller part:

 

private Partner__c cst; public Partner__c getCustomer() { if (this.cst == null) { this.cst = new Partner__c(); System.debug(Logginglevel.DEBUG, '##### getCustomer(): create new customer'); } System.debug(Logginglevel.DEBUG, '##### getCustomer(): cst.Name = ' + this.cst.Name); return this.cst; } public void setCustomer(Partner__c value) { // Use a customised setter to detect if crucial address details changed // to force the address validation or skip it. System.debug('##### setCustomer(): value -> ' + value + ', customer -> ' + cst); if ( cst <> null && (!value.City__c.equalsIgnoreCase(cst.City__c) || !value.Street__c.equalsIgnoreCase(cst.Street__c) || !value.Country__c.equalsIgnoreCase(cst.Country__c) || !value.PostalCode__c.equalsIgnoreCase(cst.PostalCode__c) ) ) { addressChanged = true; } cst = value; }

 

 VF page:

 

<apex:page title="{!currentStep}" tabStyle="Partner__c" controller="OrderWizardController" action="{!displayCustomerPage}" showHeader="true" > <apex:sectionHeader title="Add a new customer" subtitle="{!currentStep}" /> <apex:form id="theform"> <apex:pageBlock title="Customer Info" mode="edit" id="pageblock"> <apex:pageBlockButtons location="both"> <apex:commandButton action="{!step2}" value="Next"/> <apex:commandButton action="{!cancel}" value="Cancel" immediate="true"/> </apex:pageBlockButtons> <apex:pageMessages /> <apex:pageBlockSection columns="2" title="Customer Address Information" id="cstInfoSection"> <apex:inputField value="{!customer.Address__c}" required="true" id="customerAddress" /> <apex:outputText /> <apex:inputField value="{!customer.Name}" required="true" id="customerName"/> <apex:inputField value="{!customer.Name1__c}" required="true" id="customerName1"/> <apex:inputField value="{!customer.Name2__c}" /> <apex:outputText /> <apex:inputField value="{!customer.Street__c}" required="true" /> <apex:inputField value="{!customer.PostalCode__c}" /> <apex:inputField value="{!customer.City__c}" required="true" /> <apex:inputField value="{!customer.Country__c}" required="true" /> <apex:inputField value="{!customer.County__c}"/> <apex:inputField value="{!customer.State__c}"/> </apex:PageBlockSection> <apex:pageBlockSection columns="2" title="Extended Information" id="cstInfoSection2"> <!-- apex:inputField value="{!customer.Description__c}"/ --> <apex:inputField value="{!customer.EmailHome__c}"/> <apex:inputField value="{!customer.EmailBusiness__c}"/> <apex:inputField value="{!customer.PhoneHome__c}"/> <apex:inputField value="{!customer.PhoneBusiness__c}"/> <apex:inputField value="{!customer.MobileHome__c}"/> <apex:inputField value="{!customer.MobileBusiness__c}"/> <apex:inputField value="{!customer.FaxHome__c}"/> <apex:inputField value="{!customer.FaxBusiness__c}"/> </apex:PageBlockSection> </apex:pageBlock> </apex:form> </apex:page>

 

 

 

 I found in the VF develper guide that the setter is not necessary not therefore not necesarrily called.

 

<qoute>

While a getter method is always required to access values from a controller, it is not always necessary to include a setter method
to pass values into a controller. If a Visualforce component is bound to an sObject that is stored in a controller, the sObject's fields are set automatically if changed by the user, as long as the sObject is saved or updated by a corresponding action method.<quote>

Can I somehow force the setter being called to mark the sObject "as dirty"? The point is that I read the values from the sObject at first and the user is able to change it. In case of changes I need some additional steps on the next pages which aren't necessary otherwise.

 

Any help is highly appreciated.

 

TIA

 

 

I have a VF page that uses an apex:repeat block with inputFields and actionSupport. If the action is fired the data is transmitted to the controller. So from that point of view everything is fine.

 

However I'd like to do some work in the setter, checking if some special fields are changed in fact.

 

See this very simple example that illustrates the problem

 

public with sharing class Testing {

public List<Account> values
{
get
{
System.debug('GETTER' + this.values);
return this.values;
}

set
{

System.debug('SETTER' + value);

// never get to this point!!!
this.values = value;
}
}

public String inputValue { get; set; }
public String outputValue { get; set; }

public Testing()
{
System.debug('Start Testing class');
/*
values = new List<String>();
values.add('One');
values.add('Two');
values.add('Three');
*/
values = [Select Id, Name from Account limit 3];
}

public PageReference dblClickAction()
{
System.debug('dblClickAction(): inputValue -> ' + inputValue);
System.debug('dblClickAction(): outputValue -> ' + outputValue);
System.debug('dblClickAction(): values -> ' + values);

//inputValue = outputValue;
return null;
}

}

 

And this is my VF page

 

 

<apex:page controller="Testing">
<apex:form >
<apex:pageBlock id="pBlock">
<apex:repeat value="{!values}" var="val">
<apex:outputText value="{!val.Name}" />
<apex:actionRegion >
<apex:inputText value="{!val.Name}">
<apex:actionSupport action="{!dblClickAction}" rerender="pBlock" event="onchange">
<apex:param assignTo="{!inputValue}" name="inputValue" value="{!val.Name}" />
</apex:actionSupport>
</apex:inputText>
<br />
</apex:actionRegion>
</apex:repeat>
</apex:pageBlock>
</apex:form>
</apex:page>

 

 

 

 What happens is that the getter of 'values' is called and the 'onchange' event fires perfectly. The rerender renders the new value of the field in the 'outputText'. Fine, BUT the setter of 'values' is never called and I'd like to do some comparison of the record returned with the actual one before setting the new one.

 

So I have no clue HOW the value is set in fact.

 

TIA

 

DerGrobe

 

hi all,

 

i have a problem with a custom setter method not being called for a custom object on a VF page.

 

Controller part:

 

private Partner__c cst; public Partner__c getCustomer() { if (this.cst == null) { this.cst = new Partner__c(); System.debug(Logginglevel.DEBUG, '##### getCustomer(): create new customer'); } System.debug(Logginglevel.DEBUG, '##### getCustomer(): cst.Name = ' + this.cst.Name); return this.cst; } public void setCustomer(Partner__c value) { // Use a customised setter to detect if crucial address details changed // to force the address validation or skip it. System.debug('##### setCustomer(): value -> ' + value + ', customer -> ' + cst); if ( cst <> null && (!value.City__c.equalsIgnoreCase(cst.City__c) || !value.Street__c.equalsIgnoreCase(cst.Street__c) || !value.Country__c.equalsIgnoreCase(cst.Country__c) || !value.PostalCode__c.equalsIgnoreCase(cst.PostalCode__c) ) ) { addressChanged = true; } cst = value; }

 

 VF page:

 

<apex:page title="{!currentStep}" tabStyle="Partner__c" controller="OrderWizardController" action="{!displayCustomerPage}" showHeader="true" > <apex:sectionHeader title="Add a new customer" subtitle="{!currentStep}" /> <apex:form id="theform"> <apex:pageBlock title="Customer Info" mode="edit" id="pageblock"> <apex:pageBlockButtons location="both"> <apex:commandButton action="{!step2}" value="Next"/> <apex:commandButton action="{!cancel}" value="Cancel" immediate="true"/> </apex:pageBlockButtons> <apex:pageMessages /> <apex:pageBlockSection columns="2" title="Customer Address Information" id="cstInfoSection"> <apex:inputField value="{!customer.Address__c}" required="true" id="customerAddress" /> <apex:outputText /> <apex:inputField value="{!customer.Name}" required="true" id="customerName"/> <apex:inputField value="{!customer.Name1__c}" required="true" id="customerName1"/> <apex:inputField value="{!customer.Name2__c}" /> <apex:outputText /> <apex:inputField value="{!customer.Street__c}" required="true" /> <apex:inputField value="{!customer.PostalCode__c}" /> <apex:inputField value="{!customer.City__c}" required="true" /> <apex:inputField value="{!customer.Country__c}" required="true" /> <apex:inputField value="{!customer.County__c}"/> <apex:inputField value="{!customer.State__c}"/> </apex:PageBlockSection> <apex:pageBlockSection columns="2" title="Extended Information" id="cstInfoSection2"> <!-- apex:inputField value="{!customer.Description__c}"/ --> <apex:inputField value="{!customer.EmailHome__c}"/> <apex:inputField value="{!customer.EmailBusiness__c}"/> <apex:inputField value="{!customer.PhoneHome__c}"/> <apex:inputField value="{!customer.PhoneBusiness__c}"/> <apex:inputField value="{!customer.MobileHome__c}"/> <apex:inputField value="{!customer.MobileBusiness__c}"/> <apex:inputField value="{!customer.FaxHome__c}"/> <apex:inputField value="{!customer.FaxBusiness__c}"/> </apex:PageBlockSection> </apex:pageBlock> </apex:form> </apex:page>

 

 

 

 I found in the VF develper guide that the setter is not necessary not therefore not necesarrily called.

 

<qoute>

While a getter method is always required to access values from a controller, it is not always necessary to include a setter method
to pass values into a controller. If a Visualforce component is bound to an sObject that is stored in a controller, the sObject's fields are set automatically if changed by the user, as long as the sObject is saved or updated by a corresponding action method.<quote>

Can I somehow force the setter being called to mark the sObject "as dirty"? The point is that I read the values from the sObject at first and the user is able to change it. In case of changes I need some additional steps on the next pages which aren't necessary otherwise.

 

Any help is highly appreciated.

 

TIA

 

 

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
  • January 16, 2009
  • Like
  • 1