Search code examples
xpagesxpages-ssjs

How to handle value of a xp:checkBoxGroup


In my Xpage I have a checkbox group with 1 option:

<xp:checkBoxGroup id="cbSignUp"
    value="#{viewScope.interested}">
    <xp:selectItem itemLabel=""
        itemValue="true" />
    <xp:eventHandler event="onchange"
        submit="true" refreshMode="partial" refreshId="pnlUpdate" />
</xp:checkBoxGroup>

When the checkbox is initially not touched the viewScope is not available.

When I check the box the value of the viewScope is true (interested [0] true)

When I uncheck the box the value of the viewScope is an empty list (interested (empty list))

Is there any logic to be found here?

Based upon the checker I want to show or hide an EditBox in panel pnlUpdate.

For now I have

if (null == viewScope.get("interested")){
    return false;
} else{
    return true;
}

But that does not work when the viewScope contains an empty list.

How can I handle this?

It is not really clear for me what the return value of a checkbox can be reading the documentation: https://www.openntf.org/xspext/xpages%20extension%20library%20documentation.nsf/xpages-doc/xp_checkBoxGroup.html


Solution

  • You are expecting the xp:checkBoxGroup to be returning a true or false (maybe even boolean :D) value but that is not what it does. Multiple checkboxes can be ticked - therefore potentially multiple values - so how do you expect they will be represented? In this case as a list of strings (although they could be a list of any type when using the right converters).

    Relying on (request|view|session|application)Scope isn't such a great practice, actually it's kind of a bad crutch (let's thank IBM once more to show us the wrong way). It leads you to be casual about the code you write and eventually it can bite you like in this case. What I mean is that, especially with lists or maps, what you want to be returned is a consistent value without the additional code for a null check (best practices say you should make use of Collections.emptyList() or Collections.emptyMap() if the list isn't initialized or you don't need to lazy load it) but, as we said, it's kind of a forced error because you can just throw a casual viewScope. reference and think all will always be fine.

    Since you know you are using the viewScope - or any other scope for that matter - why not use what the framework knows how to do best? Managing beans!

    At this point you can write sound, defensive code, that will always help you down the way:

    The bean

    public class MyViewScopedBean implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private List<String> sweets;
    
        public List<String> getSweets() {
            if (sweets == null) {
                sweets = new ArrayList<String>();
            }
    
            return sweets;
        }
    
        public void setSweets(List<String> sweets) {
            this.sweets = sweets;
        }
    
    }
    

    The xsp

    With the above bean referenced as bean:

    <h3>Select the sweets</h3>
    
    <xp:div id="containerSweetForm">
        <xp:checkBoxGroup id="checkBoxGroup1" value="#{bean.sweets}">
            <xp:selectItem itemLabel="Biscuit" itemValue="biscuit" />
            <xp:selectItem itemLabel="Ice cream" itemValue="icecream" />
            <xp:selectItem itemLabel="Pie" itemValue="pie" />
        </xp:checkBoxGroup>
    
        <xp:button value="Tell me the sweets" id="button1">
            <xp:eventHandler event="onclick" submit="true"
                execMode="partial" execId="containerSweetForm" refreshMode="partial"
                refreshId="containerSweets" />
        </xp:button>
    </xp:div>
    
    <h3>Selected sweets</h3>
    
    <xp:div id="containerSweets">
        <xp:text value="#{bean.sweets}" />
    </xp:div>
    

    What's in the list is all the ticked checkboxes represented with their itemValue attribute.