craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.28k stars 635 forks source link

[4.x]: CP `checkboxSelect.twig` not sending empty values #11748

Closed vandres closed 2 years ago

vandres commented 2 years ago

What happened?

Description

I am using a custom field in the CP. It displays the available category groups. When displaying these category groups with multiselect.twig, everythings works as expected. But since I don't like the usability of multi selects, I want to use the multi checkbox layout.

I can see in the network pane, that when sending a new selection, the field is submitted with values.

image

When deselecting everything, nothing is sent for this field. That, I guess, is the problem. Comparing it to multiselct, an empty value is sent:

image

Steps to reproduce

  1. Create a new custom field
  2. Use the checkboxSelect.twig as input html
  3. select something
  4. save
  5. unselect all
  6. save

Expected behavior

Everything is unselected.

Actual behavior

The last state is restored, when deselecting everything.

Craft CMS version

4.2.0.2

PHP version

8.1

Operating system and version

MacOS

Database type and version

MariaDB 10.5

Image driver and version

-

Installed plugins and versions

  "require": {
    "craftcms/cms": "^4.2.0.2",
    "craftcms/commerce": "^4.1",
    "craftcms/redactor": "^3.0",
    "firephp/firephp-core": "^0.5.3",
    "php-http/curl-client": "^2.2",
    "spicyweb/craft-neo": "^3.2",
    "typesense/typesense-php": "^4.8",
    "vaersaagod/geomate": "^2.0",
    "vlucas/phpdotenv": "^5.4.0"
  },
  "require-dev": {
    "roave/security-advisories": "dev-master",
    "deployer/deployer": "^7.0",
    "yiisoft/yii2-shell": "^2.0.3"
  },
brandonkelly commented 2 years ago

This surprised me a little since we use checkboxSelect inputs all over the place and I was sure they already do post an empty value when no options are selected.

Turns out they do, but only if you pass showAllOption: true to the input config (which we typically do):

{% import "_includes/forms" as forms %}

{{ forms.checkboxSelect({
  name: 'foo',
  showAllOption: true,
}) }}

I’ve just updated the template to start posting an empty value regardless of showAllOption, however this is a slight change in behavior that could potentially break some controllers that assume the posted value will either be nonexistent or an array, so I’ve made the change for Craft 4.3 instead of the next 4.2.x release.

vandres commented 2 years ago

I can confirm, with "showAllOption" it does work. It doesn't make sense in our case, but at least I can work around it. Thank you very much!

vandres commented 2 years ago

I found another temporary workaround. I am outputting a hidden input field before the checkboxes:

        return '<input type="hidden" name="' . $this->handle . '" value="">' . Craft::$app->getView()
                ->renderTemplate('_includes/forms/checkboxSelect', [
                    'name' => $this->handle,
                    'values' => $value !== null ? $value->ids() : [],
                    'options' => $options,
                ]);
brandonkelly commented 2 years ago

Yep that’s exactly what will happen in 4.3. Your code won’t break, but after 4.3 it will be safe to remove that extra hidden input.