[SalesForce] Manage State for apex:inputCheckbox on Visualforce page when adding dynamic apex:pageBlockTable rows

I have a Visualforce page that allows a user to setup as many records (custom object called "Override") on the page as they want and then on submit all of the rows are inserted into Salesforce via the controller.

The page was created years ago and whenever we needed to add an additional field to the page all I had to do was add the apex:column and bind an apex:inputField and it just worked great.

Now the requirements have changed and I need to add a boolean, ie: a checkbox bound to apex:inputCheckbox.

enter image description here

As long as the user waits until the end, after all of the Add Rows have been called, then it's fine, the checked value is set on the new Overrides that are created.

However if the user checks the box for Preferred, then clicks Add Row (which just adds another row at the bottom), the Preferred checkbox for any checked rows becomes unchecked.

For all other values, Override Date, Override Amount (and a bunch that I took off for this demo) the values she had set before the Add Row link was clicked are persisted (I assume through viewstate), but not the Preferred checkbox.

About the only thing I can find online about this is the recommendation to use a Wrapper for your object then have an isSelected bit to manage which ones are selected, but I've been working on that and can't figure out how to utilize it.

Here's what I have for my controller & wrapper so far:

public List<OverrideWrapper> wrappers {get; set;}
public static Integer toDelIdent {get; set;}
public static Integer addCount {get; set;}
private Integer nextIdent=0;

public class OverrideWrapper
{
    public Override__c ovr {get; set;}
    public boolean isSelected{ get; set; }  
    public Integer ident {get; set;}

    public OverrideWrapper(Integer inIdent)
    {
        ident=inIdent;
        isSelected = false;
        ovr=new Override__c();
    }
}  

public multiOverrideInsertControllerV2()
{
    wrappers=new List<OverrideWrapper>();
    wrappers.add(new OverrideWrapper(nextIdent++));
}

public void delRow()
{
    Integer toDelPos=-1;
    for (Integer idx=0; idx<wrappers.size(); idx++)
    {
        if (wrappers[idx].ident==toDelIdent)
        {
            toDelPos=idx;
        }
    }

    if (-1!=toDelPos)
    {
        wrappers.remove(toDelPos);
    }
}

public void addRow()
{
    for (OverrideWrapper ovrw : wrappers)
    {
        system.debug('#### Is Selected = ' + ovrw.isSelected); 
        system.debug('#### Deposit Date = ' + ovrw.ovr.Deposit_Date__c);            
        if(ovrw.isSelected) {
            ovrw.ovr.Preferred__c = true;
        }
    }
    wrappers.add(new OverrideWrapper(nextIdent++));
}

Notice in the addRow() method, those system.debug's return null for deposit date and false for isSelected.

Can anyone point me into how to manage the state of these checkboxes?

Visualforce page per comment:

<apex:pageBlockTable value="{!wrappers}" var="w" id="table"> 
     <apex:column headerValue="Identity" rendered="false" >
        <apex:outputText value="{!w.ident}"/>
     </apex:column>                              
    <apex:column headerValue="Override Date">                      
        <apex:inputField value="{!w.ovr.Override_Date__c}" required="true" />                          
    </apex:column>  
    <apex:column headerValue="Preferred">
        <apex:inputCheckbox value="{!w.ovr.Preferred__c}" selected="{!w.isSelected}" immediate="true"  />
    </apex:column>                        
    <apex:column headerValue="Override Amount">                    
        <apex:inputField value="{!w.ovr.Override_Amount__c}" required="true" styleClass="total" onchange="calcTotal()"  />                           
    </apex:column>   
    <apex:column headerValue="Action">
        <apex:commandButton value="Delete" action="{!delRow}" rerender="table" immediate="true">
            <apex:param name="toDelIdent" value="{!w.ident}" assignTo="{!toDelIdent}"/>
        </apex:commandButton>
    </apex:column>                                               
 </apex:pageBlockTable> 

Note I've tried a number of different combinations for value and selected properties:

value="{!w.ovr.Preferred__c}" selected="{!w.isSelected}"

Best Answer

Wow, I don't know how to feel about this. The answer is, Don't use apex:inputCheckbox, always use apex:inputField when binding to a value on a controller. Apex will do the work of knowing it's a boolean and making it a checkbox.

Ouch, that was a bunch of time wasted.

Maybe someone could add this to the apex:inputCheckbox documentation, right after it says this: "Use this component to get user input for a controller method that does not correspond to a field on a Salesforce object." - to say, "If you're binding a checkbox to a controller, use apex:inputfield" and it will be rendered as a checkbox.