3

It's been a while, and I feel like I'm missing something simple/obvious but have been spinning my wheels for a while and can't find an answer.

The essence of my problem is that I cannot maintain the state of row column values in a pageBlockTable where those pageBlockTables are generated dynamically. The state is only maintained for the last table generated. I have illustrated the issue in the page/controller below and a screenshot for context:

TestPage.page

<apex:page showHeader="true" sidebar="true" controller="TestController">
    <apex:form>
        <apex:pageBlock title="Header">
            <apex:pageBlockButtons >
                <apex:commandButton value="Process" action="{!doNothing}"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="1" collapsible="false" title="Location">
                <apex:repeat var="section" value="{!Sections}">
                    <h1>{!section}</h1>
                    <apex:variable var="wrappers" value="{!Sections[section]}"/>
                    <apex:pageBlockTable value="{!wrappers}" var="wrapper" >
                        <apex:column breakBefore="true" colspan="1" >
                            <apex:inputCheckbox value="{!wrapper.isSelected}" />
                        </apex:column>
                        <apex:column headerValue="Wrapper Title" >
                            <apex:inputText value="{!wrapper.title}" />
                        </apex:column>
                    </apex:pageBlockTable>
                </apex:repeat>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

TestController.cls

public with sharing class TestController 
{
    public TestController() {}
    public PageReference doNothing()
    {
        return null;
    }

    public Map<String,List<Wrapper>> Sections
    {
        get 
        {
            if(Sections == null)
            {
                Sections =  new Map<String,List<Wrapper>>{'Section 1'=>new List<Wrapper>{new Wrapper('section 1, item 1'), new Wrapper('section 1, item 2')}, 'Section 2'=>new List<Wrapper>{new Wrapper('section 2, item 1'), new Wrapper('section 2, item 2')}};
            }
            return Sections;
        }
        set;
    }
    public class Wrapper
    {
        public Boolean isSelected {get;set;}
        public String title {get;set;}
        public Wrapper(String title)
        {
            this.title = title;
            this.isSelected = false;
        }
    }
}

Despite checking all boxes for both sections, after the Process button is clicked, only the last table has retained its state.

enter image description here

Does anyone have any bright ideas as to what I'm missing here or an explanation for this behaviour?

3

I have a feeling it may have to do with the fact that you are declaring an <apex:variable /> inside the repeater. I changed the object model a little and that is no longer necessary. This seems to do the trick.

Controller:

public with sharing class TestController 
{
    public TestController() {}
    public PageReference doNothing()
    {
        return null;
    }

    public List<Section> Sections
    {
        get 
        {
            if (Sections == null)
            {
                Sections = new List<Section>
                {
                    new Section('Section 1',
                            new List<Wrapper>{new Wrapper('section 1, item 1'), new Wrapper('section 1, item 2')}
                        ),
                    new Section('Section 2',
                            new List<Wrapper>{new Wrapper('section 2, item 1'), new Wrapper('section 2, item 2')}
                        )
                };
            }
            return Sections;
        }
        set;
    }

    public class Section
    {
        public String header {get;set;}
        public List<Wrapper> wrappers {get;set;}
        public Section(String header, List<Wrapper> wrappers)
        {
            this.header = header;
            this.wrappers = wrappers;
        }
    }

    public class Wrapper
    {
        public Boolean isSelected {get;set;}
        public String title {get;set;}
        public Wrapper(String title)
        {

            this.title = title;
            this.isSelected = false;
        }
    }
}

VF Page:

<apex:page showHeader="true" sidebar="true" controller="TestController">
    <apex:form >
        <apex:pageBlock title="Header">
            <apex:pageBlockButtons >
                <apex:commandButton value="Process" action="{!doNothing}"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="1" collapsible="false" title="Location">
                <apex:repeat var="section" value="{!Sections}">
                    <h1>{!section.header}</h1>
                    <apex:pageBlockTable value="{!section.wrappers}" var="wrapper" >
                        <apex:column breakBefore="true" colspan="1" >
                            <apex:inputCheckbox value="{!wrapper.isSelected}" />
                        </apex:column>
                        <apex:column headerValue="Wrapper Title" >
                            <apex:inputText value="{!wrapper.title}" />
                        </apex:column>
                    </apex:pageBlockTable>
                </apex:repeat>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Screenshot

Screenshot

  • 1
    Wow, I did not expect that to be the issue - thank you, I had been spinning my wheels for a while on that! – Phil Hawthorn May 5 '17 at 7:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.