function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
DerGrobeDerGrobe 

Setter for Lists

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

 

S_LieS_Lie

Hi,

 

The values is only used in the first time when the constructor start and its working. ( see below debug log )

everytime you change the inputtext it wont change the value of the 'Values' hence you wont see any debug inside the setter  .

Hope it can clarify your doubt.

 

20091216063740.027:Class.Testing.<init>: line 21, column 1: Start Testing class
20091216063740.027:Class.Testing.<init>: line 28, column 22: SOQL query with 3 rows finished in 6 ms
20091216063740.027:Class.Testing.setValues: line 7, column 5: Setter
20091216063740.027:Class.Testing.<init>: line 29, column 1: returning from end of method public void setValues(LIST:SOBJECT:Account) in 0 ms
20091216063740.027:External entry point: returning from end of method public Testing<Constructor>(ApexPages.StandardController) in 6 ms
20091216063740.027:External entry point: returning LIST:SOBJECT:Account from method public LIST:SOBJECT:Account getValues() in 0 ms
Cumulative profiling information:

1 most expensive SOQL operations:
Class.Testing.<init>: line 28, column 22: [Select Id, Name from Account limit 3]: executed 1 time in 6 ms

No profiling information for SOSL operations.

No profiling information for DML operations.

 

DerGrobeDerGrobe
Maybe my explanation was a bit misleading.

 

 

My question is why the setter isn't called when the onchange event fires. If I change the content of inputText the onchange is fired and the values is updated in the controller, but the setter isn't called. So how does it get updated?



Initial call when entering the page, everything is totally clear.

20091216081324.004:Class.Testing.: line 48, column 9: Start Testing class 20091216081324.004:Class.Testing.: line 55, column 18: SOQL query with 3 rows finished in 17 ms 20091216081324.004:Class.Testing: line 37, column 13: SETTER(Account:{Name=GMS, Id=0018000000WfUgPAAV}, Account:{Name=Acme, Id=0018000000W83rJAAR}, Account:{Name=salesforce.com, Id=0018000000W83rKAAR}) 20091216081324.004:Class.Testing.: line 55, column 9: returning from end of method public void in 0 ms 20091216081324.004:External entry point: returning from end of method public Testing() in 17 ms 20091216081324.004:Class.Testing: line 31, column 13: GETTER(Account:{Name=GMS, Id=0018000000WfUgPAAV}, Account:{Name=Acme, Id=0018000000W83rJAAR}, Account:{Name=salesforce.com, Id=0018000000W83rKAAR}) 20091216081324.004:External entry point: returning LIST:SOBJECT:Account from method public LIST:SOBJECT:Account in 0 ms


When changing the value the onchange fires and the setter is not called, although the changed values are set.


20091216081617.022:Class.Testing: line 31, column 13: GETTER(Account:{Name=GMS, Id=0018000000WfUgPAAV}, Account:{Name=Acme, Id=0018000000W83rJAAR}, Account:{Name=salesforce.com, Id=0018000000W83rKAAR}) 20091216081617.022:External entry point: returning LIST:SOBJECT:Account from method public LIST:SOBJECT:Account in 1 ms 20091216081617.022:Class.Testing.dblClickAction: line 63, column 9: dblClickAction(): inputValue -> GMS 20091216081617.022:Class.Testing.dblClickAction: line 64, column 9: dblClickAction(): outputValue -> null 20091216081617.022:Class.Testing: line 31, column 13: GETTER(Account:{Name=GMS2, Id=0018000000WfUgPAAV}, Account:{Name=Acme, Id=0018000000W83rJAAR}, Account:{Name=salesforce.com, Id=0018000000W83rKAAR}) 20091216081617.022:Class.Testing.dblClickAction: line 65, column 9: returning LIST:SOBJECT:Account from method public LIST:SOBJECT:Account in 0 ms 20091216081617.022:Class.Testing.dblClickAction: line 65, column 9: dblClickAction(): values -> (Account:{Name=GMS2, Id=0018000000WfUgPAAV}, Account:{Name=Acme, Id=0018000000W83rJAAR}, Account:{Name=salesforce.com, Id=0018000000W83rKAAR}) 20091216081617.022:External entry point: returning NULL from method public System.PageReference dblClickAction() in 1 ms Element j_id7 called method {!dblClickAction} returned type PageReference: none20091216081617.022:Class.Testing: line 31, column 13: GETTER(Account:{Name=GMS2, Id=0018000000WfUgPAAV}, Account:{Name=Acme, Id=0018000000W83rJAAR}, Account:{Name=salesforce.com, Id=0018000000W83rKAAR}) 20091216081617.022:External entry point: returning LIST:SOBJECT:Account from method public LIST:SOBJECT:Account in 0 ms Cumulative profiling information:


You see that the first call to the getter holds the old value 20091216081617.022:Class.Testing: line 31, column 13: GETTER(Account:{Name=GMS and on 2nd call 20091216081617.022:Class.Testing: line 31, column 13: GETTER(Account:{Name=GMS2 the value is updated.

So when and how is it updated? I'd like add some code to the setter that is doing that which is obviously not the setter in my code.

TIA
bob_buzzardbob_buzzard

Your setter isn't called because you don't have an input field backed by the list itself.  What you have done is to iterate a list and create a number of input fields that are backed by the name field of each account. 

 

When the value of the input field is changed, the setter for the name field of the appropriate account object is fired, which is not in your code and thus you don't see it.

 

When I've been doing similar work to this, I normally pass the id of the object through to the action method, and then extract the object from the list.  However, I suspect that you will find that the account name has been changed due to the binding before your action method fires.

 

 

DerGrobeDerGrobe

bob_buzzard wrote:
Your setter isn't called because you don't have an input field backed by the list itself.  What you have done is to iterate a list and create a number of input fields that are backed by the name field of each account. 
When the value of the input field is changed, the setter for the name field of the appropriate account object is fired, which is not in your code and thus you don't see it.


ok, understand that.

but i'm not able to create an appropriate setter for this, how should it be named? i wasn't able to find any documentation for it unfortunately.


When I've been doing similar work to this, I normally pass the id of the object through to the action method, and then extract the object from the list.  However, I suspect that you will find that the account name has been changed due to the binding before your action method fires.


exactly, the account name is already changed at that point, i checked that out first.
bob_buzzardbob_buzzard

The setter already exists - it is part of the Account sObject and allows the Name field to be changed.

 

If you want to intercept this change, you'll have to write a wrapper class for Account and provide a getter/setter for the wrapped name field. Then populate your list with wrapper classes rather than the accounts.  That way your setter will be called when the value is changed, as its your object that will be backing it. 

 

You'll have to change your input backing variable to use the wrapped class getter.  Also, the inputfield component will need to change to an inputtext, as you will no longer be backing the input with an sobject field.

DerGrobeDerGrobe

ah, ok, so some kind of "hidden magic". thanks for the info.

 

i'll check out the wrapper-class approach for my simple example and then decide if it's feasible for larger objects or if maybe setting an "prevAccount" variable it easier to handle.