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
gtuerkgtuerk 

Implementing 'Select All' button for SelectCheckboxes' Select Options

I'd like to implement a Select All button on a page requiring user interaction with Select Checkboxes.  Here's the page code with the Select All button.  How to rerender the checkboxes all checked?  I'm guessing I do this with rerender but not sure how to access the select options array?

 

<apex:pageBlockSection title="Available SOs" collapsible="false" columns="2">
            <apex:selectCheckboxes id="chkCandidateSOs" value="{!selectedItems}" >
                   <apex:selectOptions value="{!items}"/>
                   <apex:actionStatus id="checkSOs" startText="Checking all SOs...">
                           <!-- how do i update the above checkboxes in this action? -->
                       </apex:actionStatus>
            </apex:selectCheckboxes>
            <apex:outputPanel />
            <apex:commandButton value="Select All" action="{!selectAll}"
            rerender="chkCandidateSOs" status="checkSOs"/>

 

and the controller code:

 

public List<SelectOption> getItems() {
        List<SelectOption> options = new List<SelectOption>();
        for (Service_Order__c eachSO:candidateSignatureItems){
            options.add(new SelectOption(eachSO.Name,eachSO.Name));
        }
        return options;
     }
     public void selectAll(){
         //implement reset of selected checkboxes?
     }
     public void setSelectedItems(String[] selection){
         selectedItems = selection;   
     }
    
     public String[] getSelectedItems(){
         return selectedItems;   
     }

 

Is it as simple as moving the options array in the controller up in scope and setting some attribution on SelectOptions in the selectAll action?  Or do I do something in the page itself?

 

Thanks!

g

Best Answer chosen by Admin (Salesforce Developers) 

All Answers

SreerupSreerup

Hi,

 

Please try out the modifications in the VF page code.. Hope this works

 

<apex:smileytongue:ageBlockSection title="Available SOs" collapsible="false" columns="2">
            <apex:selectCheckboxes id="chkCandidateSOs" value="{!selectedItems}" >
                   <apex:selectOptions value="{!items}"/>

            </apex:selectCheckboxes>

             <apex:commandButton value="Select All" action="{!selectAll}"  rerender="chkCandidateSOs"

                status="checkSOs"/>

                 <apex:outputpanel id ="chkCandidateSOs">
                   <apex:actionStatus id="checkSOs" startText="Checking all SOs...">

                             <apex:facet name="stop">
                               <apex:dataList value="{!SelectedItems}" var = "s">{!s}</apex:dataList>    

                             </apex:facet>

                    </apex:actionStatus>

                 </apex:outputpanel>

   </apex:pageBlockSection>              

hisrinuhisrinu
This was selected as the best answer
gtuerkgtuerk
That's closer to what I want but I'd like to do this using the existing SelectCheckboxes and ideally without JS.  I moved the SelectOptions array up in scope to be a member of my controller and have a page action that is called by a command button that iterates over the array but I can't find the right method to 'uncheck' the boxes in controller code.  Ideally, visualforce and apex only, no js but if that's the only way for me to do it, I guess I'll go that route.
sfdcfoxsfdcfox

I was looking for a solution involving the apex: selectCheckboxes component, and I came across this post. I created a "pure" method for implementing a Select All box, including automatic selection/deselection if every item in the list were also selected, or not, and I thought I'd share this. It looks something like this:

 

Page fragement:

 

<apex:dataTable width="100%" rendered="{!hasitems}" value="{!inventorylist}" var="item" id="theList"> <apex:column > <apex:facet name="header"> <apex:inputcheckbox selected="{!selectall}"> <apex:actionSupport event="onchange" action="{!toggleall}" reRender="theList"/> </apex:inputcheckbox> </apex:facet> <apex:inputCheckbox value="{!item.selected}"> <apex:actionSupport event="onchange" reRender="theList" /> </apex:inputCheckbox> </apex:column>

 

 Controller fragment:

 

 

public controllerClass { // ... public list<inventoryitem> inventoryList { get; set; } public boolean hasItems { get { return !inventorylist.isempty(); } } public boolean hasNoitems { get { return inventorylist.isempty(); } } public boolean selectall { get { selectall = checklist(); return selectall; } set; } public void toggleall() { boolean temp = !selectall; for(inventoryitem item:inventorylist) { item.selected = temp; } } // ... private boolean checklist() { boolean allchecked = true; for(inventoryitem item:inventorylist) { allchecked = allchecked && item.selected; } return allchecked; } // ... }

 

 As you can see, I hardcode a checkbox that, when clicked, will trigger a function that effectively sets the entire list to the new state of the select all box. The box itself checks to see if all items in the list are selected, and if so, will check itself, otherwise it will uncheck itself. This runs purely in Visualforce Code.

 

Note that "item" is a wrapper class, so it would look like the following:

 

public class inventoryitem { public boolean selected; // -- other member values here }

 

Finally, note that inventoryList would be initialized and pre-populated by some other function. I leave this as an exercise to the reader.

Also note that the column checkboxes have an action event as well; unchecking one box will uncheck the select-all box because of the reRender, and if all boxes are checked, select-all will detect this and check itself automatically.

 

I hope this helps out some people that are looking to visualforce solutions to avoid javascript.

 

 

 

Roy Stout 6Roy Stout 6
Not sure if this question has ever been answered completely, but here is what I came up with.
Basically, you have to traverse the DOM to get to the individual checkboxes.
If SF has implemented a better solution in the last 10 years, please respond and let me know!

            function selectAll(thisTable) {
                console.log("selectAll(): " + thisTable);
                var vTBODY;
                var vTR = [];
                var vTD = [];
                var vINPUT = [];
                var checkboxIDs = [];

                // SFDC translates selectCheckboxes as:
                // <table><tr><td><input type=checkbox><input type=checkbox><input type=checkbox>...
                // The id of the selectCheckboxes is the ID of the table, passed into this function as thisTable
                // My (this file) component ID path to the pageblock containing the selectCheckboxes:
                var expr = "{!$Component.theForm.pb2}"; 

                // Completes the ID path to the selectCheckboxes we want to Select All
                // This allows you to reuse this function for multiple selectCheckboxes requiring Select All
                expr += ":" + thisTable; // note SF uses colon to concatenate path components

                // spit it out to confirm path
                console.log("B: expr: " + expr); // see how SF uses colons to separate IDs in the path

                // get all childnodes for the <table> (aka selectCheckboxes) then search for 'tbody'
                var allCheckboxes = document.getElementById(expr).childNodes;

                // look for nodeName = tbody, there is only one so Break when found
                for (i=0; i<allCheckboxes.length; i++) {
                    if (allCheckboxes[i].nodeName.toLowerCase() == "tbody") {
                        vTBODY = i;
                        break;
                    }
                }

                // get the TR in the tbody
                // There should only be 1 but which childNode?
                for (var i=0; i<allCheckboxes[vTBODY].childNodes.length; i++) {
                    if (allCheckboxes[vTBODY].childNodes[i].nodeName.toLowerCase() == "tr") {
                        vTR.push(allCheckboxes[vTBODY].childNodes[i]);
                    }
                }

                // get the TD in the TR
                // There should only be 1 but which childNode?
                for (var i=0; i<vTR.length; i++) {
                    var nodeLength = vTR[i].childNodes.length;
                    for (var j=0; j<nodeLength; j++) {
                        if (vTR[i].childNodes[j].nodeName.toLowerCase() == "td") {
                            vTD.push(vTR[i].childNodes[j]);
                        }
                    }
                }

                // get the INPUTs (type=checkbox) in the TD
                // There should be 1 for each SelectOption in the list
                for (var i=0; i<vTD.length; i++) {
                    var nodeLength = vTD[i].childNodes.length;
                    for (var j=0; j<nodeLength; j++) {
                        if (vTD[i].childNodes[j].nodeName.toLocaleLowerCase() == "input") {
                            vINPUT.push(vTD[i].childNodes[j]);
                        }
                    }
                }

                // add the INPUTs' (type=checkbox) ID to the list
                for (var k=0; k<vINPUT.length; k++) {
                    checkboxIDs.push(vINPUT[k].id);
                }

                // execute click event on each checkbox ID in the list
                for (var i=0; i<checkboxIDs.length; i++) {
                    document.getElementById(checkboxIDs[i]).click();
                    console.log("checkboxIDs[i]).checked: " + document.getElementById(checkboxIDs[i]).checked);
                }

                // since javascript executes so fast on the client to CLICK the checkboxes, and there
                // is latency reading the variable back from Saleforce, rerender the output section
                // a couple times to make sure the page shows the current state of the varable in Salesforce
                // Don't be afraid to include another rerender at 5 secs if necessary!
                // Or.. wrap this whole thing in a Promise()
                setTimeout(function() { rerenderOutput(); console.log("1 sec interval"); }, 1000);
                setTimeout(function() { rerenderOutput(); console.log("3 sec interval"); }, 3000);
            }