Iterate over a set of Neos.Fusion.Form:Checkbox

Hi everybody,

I´m not only new to Neos and this forum but also kind of getting back into “some coding” after quite some years off it. So, please bear with my, I will try my best to not proof that “there are no dump questions” statement wrong :smiley:

As a learning objective, I set myself to re-built a form that incorporates simple depedencies on checkboxes (at least one CB has to be checked) as well as connecting to an external API to send the data, to name a few and those in particular where I´m stuck.
So, I quickly ended up in the Demo package´s Contact form, adding a custom action for the external API call (which works, although propably not the Neos way but that´s for another post if I can´t figure it out myself) and the very basic task to make sure, the checkbox sections of the form behave as expected.

But here, I seem to be hard stuck as I can´t figure out how to do this. Meanwhile, I´m actually not even sure about the path I´m trying to take is right.
So, I thought, this clearly is a task for a validator. So, I´ve built a structure like this inside the fusion:

    renderer = Neos.Fusion.Form:Runtime.RuntimeForm {
        namespace = 'contact'
        process {
            content = afx`
                <fieldset>
									... some input fields like name, ...
                </fieldset>
								<fieldset>
										<legend>Please select the most appropriate description(s)</legend>  
										<Neos.Fusion.Form:FieldContainer field.name="appropriate-description" field.multiple={true}>
												<legend class="text-1xl">Legend 1</legend>
												<Neos.Fusion.Form:Checkbox field.name="case-1" />
												<legend class="text-1xl">Legend 2</legend>
												<Neos.Fusion.Form:Checkbox field.name="case-2" />
												<legend class="text-1xl">Legend 3</legend>
												<Neos.Fusion.Form:Checkbox field.name="case-3" />
												<legend class="text-1xl">Legend 4</legend>
												<Neos.Fusion.Form:Checkbox field.name="case-4" />
												<legend class="text-1xl">Legend 5</legend>
												<Neos.Fusion.Form:Checkbox field.name="case-5" />
												<legend class="text-1xl">Legend 6</legend>
												<Neos.Fusion.Form:Checkbox field.name="case-6" />
												<legend class="text-1xl">Legend 7</legend>
												<Neos.Fusion.Form:Checkbox field.name="case-7" />
										</Neos.Fusion.Form:FieldContainer>
								</fieldset>
            `

            footer = afx`
                <button type="submit">Submit</button>
            `
            schema {
								...
                appropriate-description = ${Form.Schema.array().isRequired().validator('Neos\Demo\Form\Runtime\Validation\Validator\FieldsetAppropiatedescriptionValidator')}
								...
            }
        }
....

I hoped for the FieldContainer´s name/id to become an array with all the checkbox child nodes in there but it isn´t. All I get in the FieldsetAppropiatedescriptionValidator isValid function is an empty array like so:
image

Here´s the very basic FieldsetAppropiatedescriptionValidator class:

<?php
declare(strict_types=1);

use Neos\Flow\Validation\Validator\AbstractValidator;

class FieldsetAppropiatedescriptionValidator extends AbstractValidator
{

	protected function isValid($value) {

			$this->addError('<pre>'.var_export($value, true).'</pre>', 1234567890);
	}
}

Also, when I try to validate a single checkbox as a boolean, it always shows true, regardless of the actual status of the checkbox.

So, I´m obviuosly doing something majorly wrong. All documentation I found is either not tackling those tasks or still beyond me to understand to be honest. So, I got even more confused by reading more over the last couple of days.
In this forum, I only found an old post (Form e-mail-finisher does not work for multiple checkbox-values) using fluid templates by naming all checboxes the same and setting all of them to multiple={true} but yeah, that´s fluid and also the fields need to have uinique names.

So, can somebody please point me in the right direction? Where am I taking the wrong path? Maybe, point me to a bunch of docu that I simply need to fully understand to solve my task?

Thank you very much
Andy

I think, I made some progress but still I´m not quite there yet.
I figured that the way to go seems to be to note the field.name´s of the checkbox elements in array notation incooperating the field.name of the container like so:

<Neos.Fusion.Form:FieldContainer field.name="appropriate-description">
<Neos.Fusion.Form:Checkbox field.name="appropriate-description[case-1]" />

Then, the array send to the validator is filled with keys at least and var_export looks something like this:
image

But validation still fails and I´m still not sure what´s going on.
When I now send the form, it returns with all checkboxes checked (regardless of the state of the checkboxes before send) and said array with keys but no values.

Independently of those findings, I also recognized in the rendered html that Neos is putting a “-” at the end of the for attribute of the label as well as at the end of the id´s of the checkboxes (but not the names) like so (regardless auf how the are named in fusion):

<label for="contact[appropriate-description][case-1]**-**">
	<input type="checkbox" name="contact[appropriate-description][case-1]" value="" id="contact[appropriate-description][case-1]**-**" class="form-checkbox">
</label>

So, even if I´m going to change the fusion for the checkboes to something simple like field.name=“case-1”, the rendered html still puts a “-” at the end, ending up with the result as shown above.

The hidden fields of the form are okay and looking like this:
<input type="hidden" name="contact[appropriate-description][case-1]" value="">

So, I now wonder where those “-” are coming from as I suppose that might be the reason why the actual status of the checkboxes will not be posted on submit (due to different id´s)?

Also, as I actually only need to validate for “at least one checkbox of that fieldset needs to be checked” but no max or other relations based on that, shouldn´t

appropriate-description = ${Form.Schema.array().isRequired()}

already be exactly what I´m looking for and no additional code should be needed?

Thanks!
Andy

Maybe @mficzel can help.

1 Like

I just keep outputting what I find.

The problem really seems to come down to simply why (the freaking hell :D) the form keeps sending those checkboxes in checked state (as soon as validator is in play)?

That explains why the array contains all 7 keys, hence the validator seems to work correctly actually.
That might also explain why appropriate-description = ${Form.Schema.array().isRequired()} is not working as it´s always an array, so always valid? No need for any values in that array, my fault to assume there should be values.

But what is it that keeps posting those checkboxes as checked as soon as the validator is activated?

Also, I found via system log that when I turn off the checkbox validator, the form does not send the checkboxes at all (again, whether they are checked or not doesn´t make a difference) but all other data of the form.

To get rid of the trailing “-” in the id attributes of the checkboyes, I added attributes.id="contact[appropriate-description][case-x]" to each Neos.Fusion.Form:Checkbox item which works in terms of the id of the html checkbox is rendered with that id instead of the calculated value form the prototype but it does not change the behaviour.

So, the trailing “-” seems not to be the problem and I can really nail it down to as soon as I add a validator (custom or just straight forward isRequired()) for FieldContainer with field.name=“appropriate-description” to the schema, all checkboxes are checked upon sending the form and that seems to be the actual problem (while name and email validators just work as fine).