"Add more" behaves erratically when involved with a computer twig AJAX element

Created on 28 October 2024, 11 months ago

Problem/Motivation

I built a form that has a custom composite element that has an "add more" button to add additional items. There's also a computed twig element that adds up values from the computed composite element and is configured to refresh its value automatically via AJAX.

There is some strange behavior that can occur sometimes when using "Add more". It works well the first time, but doing it a second time will sometimes remove elements that were previously added via the add more.

Here's a video demonstrating the issue. The first part of the video shows how it should work. I added 3 elements to the composite, then added an additional element, which created a total of 5 elements. Great. Then, I refreshed the page and tried again. This time the problem occurred. I added 3 elements, then added an additional element, and instead of 5 total being shown, now there are just 2. If actual data was entered in the existing rows, it would have been lost.

Note that I can repeat this experiment many times and reproduce it some of the time. In the above case, I happened to reproduce it on the 2nd attempt.

Steps to reproduce

I cannot reproduce it reliably, so I think there's a race condition with the various AJAX callbacks executing.

  1. Use the webform provided below.
  2. Use "add more" button to add 3 elements and wait for them to show up in the form.
  3. Use the "add more" button and input to add 1 additional element. I've had the best results reproducing it when I very quickly click "Add more" after decrementing the input from 3 to 1.
  4. Observe that instead of the expected 5 total elements, there are now just 2. The 3 that were added previously were removed.

Simple webform:

uuid: 2ecbb497-60a9-4aa7-ae4b-a6d2f1efa3fb
langcode: en
status: open
dependencies: {  }
weight: 0
open: null
close: null
uid: null
template: false
archive: false
id: sdspx
title: 'Computed twig issue with add more button'
description: ''
categories: {  }
elements: |-
  custom_composite_test_with_add_more:
    '#type': webform_custom_composite
    '#title': 'Custom composite test with add more'
    '#multiple': 20
    '#title_display': before
    '#multiple__sorting': false
    '#element':
      desc:
        '#type': textfield
        '#title': Description
      amount:
        '#type': number
        '#title': Amount
  total_amount:
    '#type': webform_computed_twig
    '#title': 'Total amount'
    '#template': |-
      {% set sum1 = 0 %}
      {% for value in data.custom_composite_test_with_add_more  %}
      {% if value.amount %}
        {% set sum1 = sum1 + value.amount %}
      {% endif %}
      {% endfor %}
      ${{ sum1|number_format(2, '.', ',') }}
    '#whitespace': trim
    '#ajax': true
css: ''
javascript: ''
settings:
  ajax: false
  ajax_scroll_top: form
  ajax_progress_type: ''
  ajax_effect: ''
  ajax_speed: null
  page: true
  page_submit_path: ''
  page_confirm_path: ''
  page_theme_name: ''
  form_title: both
  form_submit_once: false
  form_open_message: ''
  form_close_message: ''
  form_exception_message: ''
  form_previous_submissions: true
  form_confidential: false
  form_confidential_message: ''
  form_disable_remote_addr: false
  form_convert_anonymous: false
  form_prepopulate: false
  form_prepopulate_source_entity: false
  form_prepopulate_source_entity_required: false
  form_prepopulate_source_entity_type: ''
  form_unsaved: false
  form_disable_back: false
  form_submit_back: false
  form_disable_autocomplete: false
  form_novalidate: false
  form_disable_inline_errors: false
  form_required: false
  form_autofocus: false
  form_details_toggle: false
  form_reset: false
  form_access_denied: default
  form_access_denied_title: ''
  form_access_denied_message: ''
  form_access_denied_attributes: {  }
  form_file_limit: ''
  form_attributes: {  }
  form_method: ''
  form_action: ''
  share: false
  share_node: false
  share_theme_name: ''
  share_title: true
  share_page_body_attributes: {  }
  submission_label: ''
  submission_exception_message: ''
  submission_locked_message: ''
  submission_log: false
  submission_excluded_elements: {  }
  submission_exclude_empty: false
  submission_exclude_empty_checkbox: false
  submission_views: {  }
  submission_views_replace: {  }
  submission_user_columns: {  }
  submission_user_duplicate: false
  submission_access_denied: default
  submission_access_denied_title: ''
  submission_access_denied_message: ''
  submission_access_denied_attributes: {  }
  previous_submission_message: ''
  previous_submissions_message: ''
  autofill: false
  autofill_message: ''
  autofill_excluded_elements: {  }
  wizard_progress_bar: true
  wizard_progress_pages: false
  wizard_progress_percentage: false
  wizard_progress_link: false
  wizard_progress_states: false
  wizard_start_label: ''
  wizard_preview_link: false
  wizard_confirmation: true
  wizard_confirmation_label: ''
  wizard_auto_forward: true
  wizard_auto_forward_hide_next_button: false
  wizard_keyboard: true
  wizard_track: ''
  wizard_prev_button_label: ''
  wizard_next_button_label: ''
  wizard_toggle: false
  wizard_toggle_show_label: ''
  wizard_toggle_hide_label: ''
  wizard_page_type: container
  wizard_page_title_tag: h2
  preview: 0
  preview_label: ''
  preview_title: ''
  preview_message: ''
  preview_attributes: {  }
  preview_excluded_elements: {  }
  preview_exclude_empty: true
  preview_exclude_empty_checkbox: false
  draft: none
  draft_multiple: false
  draft_auto_save: false
  draft_saved_message: ''
  draft_loaded_message: ''
  draft_pending_single_message: ''
  draft_pending_multiple_message: ''
  confirmation_type: page
  confirmation_url: ''
  confirmation_title: 'Thank you!'
  confirmation_message: '<p>Your submission has been received.</p>'
  confirmation_attributes: {  }
  confirmation_back: true
  confirmation_back_label: ''
  confirmation_back_attributes: {  }
  confirmation_exclude_query: false
  confirmation_exclude_token: false
  confirmation_update: false
  limit_total: null
  limit_total_interval: null
  limit_total_message: ''
  limit_total_unique: false
  limit_user: null
  limit_user_interval: null
  limit_user_message: ''
  limit_user_unique: false
  entity_limit_total: null
  entity_limit_total_interval: null
  entity_limit_user: null
  entity_limit_user_interval: null
  purge: none
  purge_days: null
  results_disabled: false
  results_disabled_ignore: false
  results_customize: false
  token_view: false
  token_update: false
  token_delete: false
  serial_disabled: false
access:
  create:
    roles:
      - anonymous
      - authenticated
    users: {  }
    permissions: {  }
  view_any:
    roles: {  }
    users: {  }
    permissions: {  }
  update_any:
    roles: {  }
    users: {  }
    permissions: {  }
  delete_any:
    roles: {  }
    users: {  }
    permissions: {  }
  purge_any:
    roles: {  }
    users: {  }
    permissions: {  }
  view_own:
    roles: {  }
    users: {  }
    permissions: {  }
  update_own:
    roles: {  }
    users: {  }
    permissions: {  }
  delete_own:
    roles: {  }
    users: {  }
    permissions: {  }
  administer:
    roles: {  }
    users: {  }
    permissions: {  }
  test:
    roles: {  }
    users: {  }
    permissions: {  }
  configuration:
    roles: {  }
    users: {  }
    permissions: {  }
handlers: {  }
variants: {  }

Proposed resolution

I suspect there's a race condition here with the AJAX callbacks. I think what may be happening is if you trigger a field change to any of the fields and then quickly click "Add more" to add additional fields, something is confused in the backend.

One thing that may help is to remove the "Add more" number input from the list of computed twig trigger elements. There's no reason that computed twig elements would need to be refreshed when this form input is changed. When I removed it from the list of triggers, I was unable to reproduce the problem. But, I'm not sure if the other inputs in the composite element being refreshed quickly before the "Add more" button is clicked will still trigger the problem.

Remaining tasks

User interface changes

API changes

Data model changes

πŸ› Bug report
Status

Active

Version

6.2

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States bkosborne New Jersey, USA

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

Merge Requests

Comments & Activities

  • Issue created by @bkosborne
  • Pipeline finished with Failed
    11 months ago
    Total: 50s
    #323331
  • πŸ‡ΊπŸ‡ΈUnited States bkosborne New Jersey, USA
  • Pipeline finished with Failed
    8 months ago
    Total: 758s
    #395126
  • Pipeline finished with Failed
    8 months ago
    Total: 932s
    #395516
  • Pipeline finished with Failed
    8 months ago
    Total: 1049s
    #395530
  • Pipeline finished with Success
    8 months ago
    Total: 817s
    #395551
  • Pipeline finished with Skipped
    8 months ago
    #395577
  • Pipeline finished with Success
    5 months ago
    Total: 318s
    #474903
  • Status changed to Postponed: needs info 13 days ago
  • πŸ‡ΊπŸ‡ΈUnited States jrockowitz Brooklyn, NY

    I am not able to replicate this issue using the attached webform via Drupal 11.x and Webform 6.3.x

    I agree that the issue might be racing condition.

    Are you able to replicate the problem using the attached webform?

Production build 0.71.5 2024