js: New comparators added too late

Created on 19 July 2023, over 1 year ago
Updated 20 July 2023, over 1 year ago

Problem/Motivation

conditional_fields.js adds additional comparators in Drupal.states.Dependent.comparisons, like this:

Drupal.behaviors.statesModification = {
  weight: -10,
  attach: function (context, settings) {
    if (Drupal.states) {
      [..]
      Drupal.states.Dependent.comparisons['Array'] = function (reference, value) {...}
      [..]
      Drupal.states.Dependent.comparisons.Object = function (reference, value) {...}

Unfortunately, in some cases, the conditions have to be evaluated _before_ this behavior fires.
This is because the weight: -10 does not really change the order of behaviors.
(unfortunately, https://www.drupal.org/project/behavior_weights was not ported to D8/D8/D10)

In our case, this was when using slim_select with conditional_fields.
But it seems the problem is really independent of slim_select.

I used the js debugger to check the order of behaviors, and the Drupal.behaviors.statesModification was _not_ pushed to the start according to its weight.

Steps to reproduce

  1. Install slim_select, conditional_fields.
  2. New taxonomy vocab, create a few terms.
  3. New content type.
  4. New field, taxonomy reference, multiple value, widget = multi select (will be converted by slim_select)
  5. New field, text.
  6. New field condition, let the text field be visible dependent on a specific term.
  7. Visit the form to create new content of the type.
  8. Add the special term in the widget.
  9. (-> text field shows up)
  10. Fill the text field.
  11. Save.
  12. Edit again.

Expected:
When editing again, the text field is visible.

Actual:
When editing again, the text field is not visible.

Proposed resolution

We need to add the new comparators earlier in the request.

We can simply skip Drupal.behaviors and do this instead:
Add the comparators as soon as the js file is included.
Use (() => {...})() for encapsulation. Or maybe don't.

  (() => {
    if (Drupal.states) {
      [...]
      Drupal.states.Dependent.comparisons['Array'] = function (reference, value) {...}
      [...]
  })();

Remaining tasks

User interface changes

API changes

Data model changes

🐛 Bug report
Status

Needs review

Version

4.0

Component

Javascript

Created by

🇩🇪Germany donquixote

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @donquixote
  • 🇧🇪Belgium nonom Brussels

    The proposed solution works for me.

  • Status changed to Needs review over 1 year ago
  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 8.0 & MySQL 5.7
    last update over 1 year ago
    130 pass
  • 🇧🇪Belgium nonom Brussels

    Thanks #1

    It's probably affecting to any comparision so I did a quick patch (needs work) If anyone have the same issue like me trying fire the proper state at page load with a given condition.

    On my case a field should be visible or not visible depending the chosen value from a multiselect. But loading the page doesn't fire the proper state. Actually only works for me with single selects, but not for complex multi selects. So the comparators have sense to be added earlier.

    Patch attached as proof of concept.

Production build 0.71.5 2024