Required fields if unchecked (Uniform)

Hi everybody

I’m using Uniform and I was wondering how to set required field if a checkbox is unchecked only.

My basic input, checked by default

<input type="checkbox" name="identique" value="1" checked>Identique</span>

And this is the form

        <span class="toggle"><?php echo l::get('prenom') ?></span><input class="toggle" name="prenom_liv" placeholder="..." value="<?php echo $form->old('prenom_liv'); ?>">
        <span class="toggle"><?php echo l::get('nom') ?></span><input class="toggle" name="nom_liv" placeholder="..."  value="<?php echo $form->old('nom_liv'); ?>">
        <span class="toggle"><?php echo l::get('adresse') ?></span><input class="toggle" name="adresse_liv" placeholder="..." value="<?php echo $form->old('adresse_liv'); ?>">
        <span class="toggle"><?php echo l::get('ville') ?></span><input class="toggle" name="ville_liv" placeholder="..." value="<?php echo $form->old('ville_liv'); ?>">
        <span class="toggle"><?php echo l::get('postal') ?></span><input class="toggle" name="postal_liv" placeholder="..." value="<?php echo $form->old('postal_liv'); ?>">
        <span class="toggle"><?php echo l::get('pays') ?></span><input class="toggle border" name="pays_liv" placeholder="..." value="<?php echo $form->old('pays_liv'); ?>">

Actually, my controller looks like this, with all field required by default

'prenom_liv' => [
         'rules' => ['required'],
         'message' => l::get('noprenomliv'),
      ],
      'nom_liv' => [
         'rules' => ['required'],
         'message' => l::get('nonomliv'),
      ],
      'adresse_liv' => [
         'rules' => ['required'],
         'message' => l::get('noadresseliv'),
      ],
      'postal_liv' => [
         'rules' => ['required'],
         'message' => l::get('nopostalliv'),
      ],
      'ville_liv' => [
         'rules' => ['required'],
         'message' => l::get('novilleliv'),
      ],
      'pays_liv' => [
         'rules' => ['required'],
         'message' => l::get('nopaysliv'),
      ],

I think I have to set up my controller with an “if” statement but I don’t know how to do it.
Every help would be appreciate. Thanks

I’m afraid I don’t understand, a checkbox can either be checked or unchecked, if you want to allow it to be unchecked, it does not make sense to require it? Require what exactly?

It only make sense to require a checkbox field if a user has to agree to something (for example, legal stuff a user has to agree to before submitting the form), but then the box may not be unchecked.

Sorry to not be clear.
My form is an online payment form by check. The first fields indicate the name, first name, address, etc… of the billing address and the other fileds indicate the name, first name, address of the delivery address.
Like paypal, the checkbox “delivery address” is checked by default, if the user has a delivery address identical to the billing adress (the most classic case). If the user uncheck the box, the name, first name, address for the delivery address fields appear (JS), and these fields are becoming required (PHP)

https://media.giphy.com/media/tbFdmmg6Pelfa/giphy.gifhttps://media.giphy.com/media/tbFdmmg6Pelfa/giphy.gif

I would suggest the following progressive enhancement:

  • add delivery address fields to the form and make them required
  • when no JS available, let the user fill in the delivery address manually (even when it is the same as billing address)
  • when JS is available, add the checkbox field to the form (checked) and hide the billing address fields from view, but “populate” them via javascript by using onblur event handlers on the billing address fields.
  • when the user unchecks the checkbox, clear all the delivery address fields and make them visible.

This way you’ll only need 1 validation on the server.

– Edit:
Now that I think of it: you could also use 1 onsubmit handler on the form to populate the “delivery address” inputs.

You can dynamically modify the rules array in the controller before you instantiate the form object:

$rules = [
   'prenom_liv' => [
      'rules' => ['required'],
      'message' => l::get('noprenomliv'),
   ],
   ...
];

if (get('identique') !== '1') {
   $notRequired = ['prenom_liv', 'nom_liv', ...];
   foreach ($rules as $name => $r) {
      if (in_array($name, $notRequired)) {
         array_shift($r['rules']);
      }
   }
}

$form = new Form($rules);
2 Likes

I’m having a problem with this method you suggests to use.

UPDATE

I’m having this error

array_shift() expects parameter 1 to be array, null given

and it points to this line

array_shift($r['rules']);

I also tried to do the opposite, eg. using array_push instead of array_shift but without any difference.

Question: in order to differentiate the billing address to the delivery address, I appended to all billing rules a _bl at the end of the string, as a way to not duplicate the same key. That’s the way to go, right? Or should it use the same key / value pairs? I keep getting confused by forms everytime.

  $rules = [
    'email' => [
       'rules' => ['required', 'email'],
       'message' => 'Email is required',
    ],
    'first_name' => [
      'rules' => ['required'],
      'message' => 'First Name is required',
    ],
    'last_name' => [
      'rules' => ['required'],
      'message' => 'Last Name is required',
    ],
    'first_name_bl' => [], 
    'last_name_bl' => [],
  ];

  if (get('same_address') !== '1') {
    $notRequired = ['first_name_bl', 'last_name_bl'];
    foreach ($rules as $name => $r) {
      if (in_array($name, $notRequired)) {
        array_push($r['rules']);
      }
    }
  }

  $form = new Form($rules);

Thanks!
af


UPDATE

so it seems that the above error happens because $rules is null, and not an array. If I change the array_shift function to

array_push($r);

I get no more problem in either cases, but (of course) the array_shift function does not take place.

How does exactly work this function, especially the array_shift($r['rules']); bit? I can’t find any example online of passing an extra argument (?) to the $r array.

  if (get('same_address') !== '1') {
    $notRequired = ['first_name_bl', 'last_name_bl', 'company_bl', 'street_address_bl', 'postal_code_bl', 'city_bl', 'state_province_bl', 'country_bl'];
    foreach ($rules as $name => $r) {
      if (in_array($name, $notRequired)) {
        array_shift($r['rules']);
      }
    }
  }

Hm, I would expect that in case that in case the condition is true, I would want to remove the complete rule from the rules array? If that is the case, you can do the following:

if (in_array($name, $notRequired)) {
  unset($rules[$name]);
}

Strangely not working!

:face_with_monocle:

for some reasons it works in the opposite way:

  • if i thick the same address checkbox, meaning it should take out some rules, it prints out all the rules but leaving the extra rules empty (because unfilled)
  • if i thick off the checkbox, and fill out all the form, i get cut out the extra rules

i’ve been double checking if the if condition at the top of this bit of code matches with what’s in the template, and it does.

Well, I don’t know what is in your template, but from a logical point of view, the condition should be:

if (get('same_address') === '1') {

Which would translate to: if the same address checkbox is ticked, remove the rules for all input fields that are in the $notRequired array.

Yep! :sweat_smile:

Working like a charm!