XF 2.2 Checkboxes - Check/Uncheck all option?

Fullmental

Active member
I have a template I've designed that works with a custom addon to dynamically create a checkbox list of attachments in a post for the user to manage. I want the user to be able to use a single checkbox at the bottom of the list to check/uncheck all individual attachments in the list. I can't seem to get it to work nicely with the xf:checkbox element in Xenforo - I can only get it to work if I manually define the HTML, but then it doesn't inherit the XF styling or necessarily follow the design standards. What's the correct way to handle a check/uncheck all option for xf:checkbox? There must be a way to do this, I've seen "select all" options within default views like the attachments page in ACP for example.
 
Last edited:
Solution
Figured out a solution. Updated the script to select elements by name and input type instead of by class. Example:

Code:
<script>
document.addEventListener('DOMContentLoaded', function() {
    var checkAllInput = document.querySelector('#checkAll input[type="checkbox"]');
    var attachmentCheckboxInputs = document.querySelectorAll('input[type="checkbox"][name^="attachments["]');
    
    if (checkAllInput) {
        checkAllInput.addEventListener('change', function() {
            attachmentCheckboxInputs.forEach(function(checkbox) {
                checkbox.checked = checkAllInput.checked;
            });
        });
    }
});
</script>
Perhaps some context might be in order. Here's the current template I have, I'm running a foreach loop to generate a list of each attachment in a post with a checkbox. They start all checked, and I have a "checkAll" checkbox that is what I want to select or unselect all checkboxes in the list of attachments. Then I have a snippet of javascript which should be handling the onclick action when a person clicks the checkAll checkbox. This worked before I implemented the use of xf:checkbox to manage the checkbox rendering and styling. Now it does not. No idea why?


This works, but is not styled correctly:
Code:
<xf:form action="{{ link('posts/better-managed-attachments', $post) }}" method="post">
    <xf:if is="$attachments">
        <p>{{ phrase('nuzforums_attachments_found', {'count': $attachments|count}) }}</p>
        <ul>
            <xf:foreach loop="$attachments" value="$attachment">
                <li>
                    <input type="checkbox" class="attachment-checkbox" name="attachments[{$attachment.attachment_id}]" value="1" checked="checked" />
                    Attachment #{$attachment.attachment_id} - {$attachment.filename}
                </li>
            </xf:foreach>
        </ul>
    </xf:if>

    <xf:if is="!$attachments">
        <p>{{ phrase('nuzforums_no_attachments') }}</p>
    </xf:if>

    <div>
        <label style="iconic">
            <input type="checkbox" id="checkAll" value="1" checked="checked" />
            {{ phrase('check_all') }}
        </label>
    </div>
    <div style="margin-top:40px">
        <input type="checkbox" name="acknowledge" required="true" />
        {{ phrase('nuzforums_acknowledge_beta') }}
    </div>
    <div class="formSubmitRow">
        <button type="submit" class="button button--icon button--icon--confirm">
            <span class="button-text">{{ phrase('confirm') }}</span>
        </button>
        <a href="{{ link('posts', $post) }}" class="button button--icon button--icon--cancel">
            <span class="button-text">{{ phrase('cancel') }}</span>
        </a>
    </div>
    <input type="hidden" name="_xfToken" value="{{ csrf_token('post') }}" />
</xf:form>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        const checkAll = document.getElementById('checkAll');
        const attachmentCheckboxes = document.querySelectorAll('.attachment-checkbox');
        checkAll.addEventListener('change', function() {
            attachmentCheckboxes.forEach(function(checkbox) {
                checkbox.checked = checkAll.checked;
            });
        });
    });
</script>

Result:

1738538084723.webp

When I use xf:checkbox to add the correct styling, the javascript event listener stops working:

Code:
<xf:form action="{{ link('posts/better-managed-attachments', $post) }}" method="post">
    <xf:if is="$attachments">
        <p>{{ phrase('nuzforums_attachments_found', {'count': $attachments|count}) }}</p>
        <ul>
            <xf:foreach loop="$attachments" value="$attachment">
                <li style="list-style-type: none; padding-left: 0;">
                    <xf:checkbox class="attachment-checkbox" name="attachments[{$attachment.attachment_id}]" value="1" checked="checked">
                        <xf:option value="1">{{ phrase('attachment_number', {'id': $attachment.attachment_id, 'filename': $attachment.filename}) }}</xf:option>
                    </xf:checkbox>
                </li>
            </xf:foreach>
        </ul>
    </xf:if>

    <xf:if is="!$attachments">
        <p>{{ phrase('nuzforums_no_attachments') }}</p>
    </xf:if>

    <div>
        <xf:checkbox id="checkAll" value="1" checked="checked">
            <xf:option value="1">{{ phrase('check_all') }}</xf:option>
        </xf:checkbox>
    </div>

    <div style="margin-top:40px">
            <xf:checkbox name="acknowledge" required="true" value="1">
                <xf:option value="1">{{ phrase('nuzforums_acknowledge_beta') }}</xf:option>
            </xf:checkbox>
    </div>

    <div class="formSubmitRow">
        <button type="submit" class="button button--icon button--icon--confirm">
            <span class="button-text">{{ phrase('confirm') }}</span>
        </button>
        <a href="{{ link('posts', $post) }}" class="button button--icon button--icon--cancel">
            <span class="button-text">{{ phrase('cancel') }}</span>
        </a>
    </div>
    <input type="hidden" name="_xfToken" value="{{ csrf_token('post') }}" />
</xf:form>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        const checkAll = document.getElementById('checkAll');
        const attachmentCheckboxes = document.querySelectorAll('.attachment-checkbox');
        checkAll.addEventListener('change', function() {
            attachmentCheckboxes.forEach(function(checkbox) {
                checkbox.checked = checkAll.checked;
            });
        });
    });
</script>

Result, looks nice but the check/uncheck all doesn't function:

1738538717770.webp

The actual checkboxes for the attachments do function, and on this page it deletes what is checked. I verified that post controller logic works regardless of what method I use to display here, HTML or xf:button.

I assume the checkAll box isn't working because the attachment checkboxes themselves are technically no longer rendered as standard HTML checkboxes, and instead are abstracted by XF in some way. However, I'm not sure how to appropriately reference these, nor am I entirely sure where to go in the docs to find this specific checkbox element and how it works either - a search yields next to no results.
 
Figured out a solution. Updated the script to select elements by name and input type instead of by class. Example:

Code:
<script>
document.addEventListener('DOMContentLoaded', function() {
    var checkAllInput = document.querySelector('#checkAll input[type="checkbox"]');
    var attachmentCheckboxInputs = document.querySelectorAll('input[type="checkbox"][name^="attachments["]');
    
    if (checkAllInput) {
        checkAllInput.addEventListener('change', function() {
            attachmentCheckboxInputs.forEach(function(checkbox) {
                checkbox.checked = checkAllInput.checked;
            });
        });
    }
});
</script>
 
Solution
Back
Top Bottom