Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DX] Introduce a server-side conditional system (to possibly replace #states) #5750

Open
klonos opened this issue Aug 29, 2022 · 2 comments
Open

Comments

@klonos
Copy link
Member

klonos commented Aug 29, 2022

This came up as an idea in #5348 (comment)

@quicksketch

This issue ... may also be helpful if we were to ever add a server-side conditional system to replace #states. By separating out the required message into its own property, we could conditionally display the required message without executing the entire form _validate() handler.

The #states property is a front-end only implementation. The lack of any server-side processing means any hidden fields cannot be required, or special validation handlers need to be added that validate field requireness manually.

Proposal

Introduce a new Form API property for designating conditional processing of parts of a form. This property would hide/show elements on the front end (like #states does already), but would also conditionally skip processing for hidden parts of the form. Hidden parts of the form would skip:

  • Processing of the #required attribute on hidden fields
  • Processing of #element_validate handlers on hidden fields
  • Remove any values from $form_state['values'] for hidden fields
@quicksketch
Copy link
Member

quicksketch commented Aug 29, 2022

I updated the summary with a bit more detail.

One of the big problems with conditional validation is that the most obvious way to identify form elements is by its key, or an array of parents. We do this for things like #limit_validation_errors, where a button is assigned a list of parents to validate only part of a form.

With conditional form elements, specifying a full list of parents could be difficult, because we're often assembling only part of a form, such as when building a field widget, or the configuration form for a block. This form partial could be placed in any number of form structures.

To solve for this, I think we could introduce relative tree traversal, matching the paradigms used in operating systems. Two periods could mean "up one parent" and one period could mean "relative to myself".

Some hypothetical syntax below...

Given a controlling element like a checkbox that hide/shows other parts of the form:

$form['parent1']['parent2']['display_title'] = array(
  '#type' => 'checkbox',
);

Conditionally shown element adjacent to the checkbox:

$form['parent1']['parent2']['title_size'] = array(
  '#type' => 'select',
  '#conditional' => array(
    array(
      'element' => array('.', 'display_title'),
      'value' => TRUE,
    ),
  ),
);

Conditionally shown element with a different parent:

$form['parent1']['parent3']['title_size'] = array(
  '#type' => 'select',
  '#conditional' => array(
    array(
      'element' => array('..', 'parent2', 'display_title'),
      'value' => TRUE,
    ),
  ),
);

The #states system also supports AND/OR and even XOR. We could either mimic that approach or try to come up with something better: https://www.lullabot.com/articles/form-api-states

@klonos klonos changed the title Introduce a server-side conditional system (to possibly replace #states) [DX] Introduce a server-side conditional system (to possibly replace #states) Sep 1, 2022
@klonos
Copy link
Member Author

klonos commented Sep 2, 2022

I really like the idea for this feature. Having been working in UX-related issues and using #states a lot, I have come to become familiar with its oddities/limitations and undocumented features (or bugs 😅 😓 ) ...I would really like us to expore this alternative here.

To solve for this, I think we could introduce relative tree traversal, matching the paradigms used in operating systems. Two periods could mean "up one parent" and one period could mean "relative to myself".

Another idea would be to use the .. and . for "one level up" and "current level", but then join parents by dots, similar to how we refer to config settings. So instead of:

  • 'element' => array('.', 'display_title'),
  • and 'element' => array('..', 'parent2', 'display_title'),

...we could be doing:

  • 'element' => '.display_title',
  • and 'element' => '..parent2.display_title',

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants