Skip to content

Closes #5156: Fix Update Preview and Add Another Item Reorder Issue for AZ Ranking#5309

Open
kevdevlu wants to merge 12 commits intomainfrom
issue/5156
Open

Closes #5156: Fix Update Preview and Add Another Item Reorder Issue for AZ Ranking#5309
kevdevlu wants to merge 12 commits intomainfrom
issue/5156

Conversation

@kevdevlu
Copy link
Copy Markdown
Member

@kevdevlu kevdevlu commented Feb 13, 2026

Description

Closes #5156 - ranking widget previews getting out of sync with their form fields after drag-and-drop reordering and clicking ajax buttons: "Update Preview", "Add Another Item", or "Remove".

The Core Problem

In formElement(), we set both details (form elements like textfields and selects) and preview_wrapper (that renders the preview for the ranking item). The KEY ISSUE is: after formElement() returns, Drupal's Form API treats these two children differently:

  • details contains standard form elements (#type => textfield, select, etc.). The Form API automatically populates their #value from user input, keyed by the original form delta. This means after drag-and-drop reorder, the fields always show the correct data for their row.

  • preview_wrapper is a plain render array (#theme => az_ranking). The Form API does not touch render arrays — whatever values are set in formElement() remain as-is. The preview was originally built from $items[$delta], which could be in a different order than user input during AJAX rebuilds.

The Fix

If the fields are ALWAYS in the right order after ajax requests, why not build previews using the same Drupal form processing pipeline as the fields?! So instead of fidgeting / playing around with widgetState and trying to hack the deltas / original deltas using some sort of mapping: WE JUST BUILD THE PREVIEW AFTER the fields have been built.

  • Use #after_build callback:
    $element['#after_build'][] = [$this, 'afterBuildRebuildPreview'];
    This builds the preview from the same Form API-populated #value sources as the form fields. We use this to replace the current function that builds from $item (buildRankingPreview()).
  • The media field required special treatment...since the media library widget's #value structure differs from simple form elements. We just read from $form_state->getUserInput() to ensure it matches the same delta order as text fields.
  • Table-drag handles visual row reordering on the client by moving entire table rows (preview + fields together), so no server-side delta remapping is needed (yay!)

Release notes

Related issues

How to test

Make sure az_paragraphs_rankings is enabled

  • Create a ranking paragraph with 4+ ranking items (mix of "standard" and "image_only" types)
  • Verify previews render correctly on initial page load
  • Drag-and-drop to reorder items once or multiple times, then click "Update Preview" or "Add Another Item" — verify previews match their corresponding fields
  • Specifically test that image_only rankings keep their images on the correct card after reorder
  • Test collapse/expand of "Edit Ranking" details panels after reorder
  • Test the "Remove" button (on new items and existing items) after reorder
  • Test removing an existing item, and then creating a new item
  • Save the form and verify the saved order is correct

Types of changes

Arizona Quickstart (install profile, custom modules, custom theme)

  • Patch release changes
    • Bug fix
    • Accessibility, performance, or security improvement
    • Critical institutional link or brand change
    • Adding experimental module
    • Update experimental module
  • Minor release changes
    • New feature
    • Breaking or visual change to existing behavior
    • Upgrade experimental module to stable
    • Enable existing module by default or database update
    • Non-critical brand change
    • New internal API or API improvement with backwards compatibility
    • Risky or disruptive cleanup to comply with coding standards
    • High-risk or disruptive change (requires upgrade path, risks regression, etc.)
  • Other or unknown
    • Other or unknown

Drupal core

  • Patch release changes
    • Security update
    • Patch level release (non-security bug-fix release)
    • Patch removal that's no longer necessary
  • Minor release changes
    • Major or minor level update
  • Other or unknown
    • Other or unknown

Drupal contrib projects

  • Patch release changes
    • Security update
    • Patch or minor level update
    • Add new module
    • Patch removal that's no longer necessary
  • Minor release changes
    • Major level update
  • Other or unknown
    • Other or unknown

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My change requires release notes.

@kevdevlu kevdevlu requested review from a team as code owners February 13, 2026 05:33
@kevdevlu kevdevlu self-assigned this Feb 13, 2026
@kevdevlu kevdevlu added the bug Something isn't working label Feb 13, 2026
@tadean tadean self-requested a review February 13, 2026 16:45
@kevdevlu
Copy link
Copy Markdown
Member Author

kevdevlu commented Feb 13, 2026

Test Cases

A working fix will be able to solve all 3 of these issues:

  1. Removal of existing ranking card causing errors after removal. How to reproduce:
    Make 4 rankings.
    a. Initial order is: A B C D
    b. Move A to position 3, so it': B C A D
    c. Move D to position 2, so it's B D C A
    d. Remove the last ranking
    e. Clicking on Update Preview and Add Another Item return Error: Call to a member function isEmpty() on null in Drupal\az_ranking\Plugin\Field\FieldWidget\AZRankingWidget->formElement() (line 144) errors
    Screen record: https://emailarizona-my.sharepoint.com/:v:/g/personal/kevinwlu_arizona_edu/IQAJNntRWcyKRKMBEXAF1sAcAexwDhgTWak_FsjsHouNyTM?e=6dJ18Q

  2. On main branch, do the same steps as above:
    Make 4 rankings.
    a. Initial order is: A B C D
    b. Move A to position 3, so it': B C A D
    c. Move D to position 2, so it's B D C A
    d. Remove the last ranking
    e. Add a new ranking produces an empty New Ranking Card with no fields (this is an issue with the deltas messing with the unique id's used by the form API states).
    Screen record: https://emailarizona-my.sharepoint.com/:v:/g/personal/kevinwlu_arizona_edu/IQBBbJQwHP8OQqwxvieLpCWnAZJBf6WzWFLEOP84h9brPeo?e=KbDXSx

  3. After all fixes, ensure the initial problem case from the az_ranking re-order preview issue #5156 are fixed. How to reproduce: same steps as 1 above:
    a. Initial order is: A B C D
    b. Move A to position 3, so it': B C A D
    c. Move D to position 2, so it's B D C A
    d. Click on Update Preview. Make sure previews and fields are in B D C A order.
    e. Click on Add Another Item. Make sure previews and fields are in B D C A order.
    f. Click on Remove on the newly added item. Make sure previews and fields are in B D C A order.

The #after_build callback builds previews from Form API-populated values (which are always in the correct order after re-ordering). Our method before was messy and unreliable: trying to use widget_state and deltas to guess where the preview should go.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes a bug where ranking widget previews become out of sync with their corresponding form fields after drag-and-drop reordering and triggering AJAX actions (Update Preview, Add Another Item, or Remove buttons). The core issue was that previews were built from $items which could be in a different order than user input during AJAX rebuilds, while form fields were automatically populated by Drupal's Form API in the correct order.

Changes:

  • Replaced preview building logic from $items to use Form API-populated field values via an #after_build callback
  • Removed the buildRankingPreview() method that built previews from $items in the wrong order
  • Added afterBuildRebuildPreview() static method that builds previews from form field #value properties after the Form API has processed them

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

kevdevlu and others added 2 commits February 18, 2026 08:36
…vior

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@kevdevlu kevdevlu requested a review from Copilot February 18, 2026 15:52
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 18, 2026

@kevdevlu I've opened a new pull request, #5322, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 18, 2026

@kevdevlu I've opened a new pull request, #5323, to work on those changes. Once the pull request is ready, I'll request review from you.

- Use $media_input === NULL instead of !$form_state->isRebuilding()
  to detect initial load, covering validation errors and other
  non-rebuilding states where user input is present.
- Build CSS classes as an array using explode/array_filter/array_merge
  instead of string concatenation to avoid duplicate spaces.
@az-digital-bot
Copy link
Copy Markdown
Contributor

Tugboat has finished building the preview for this pull request!

Link:

Dashboard:

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

az_ranking re-order preview issue

4 participants