Closes #5156: Fix Update Preview and Add Another Item Reorder Issue for AZ Ranking - #5309
Closes #5156: Fix Update Preview and Add Another Item Reorder Issue for AZ Ranking#5309kevdevlu wants to merge 13 commits into
Update Preview and Add Another Item Reorder Issue for AZ Ranking#5309Conversation
Test CasesA working fix will be able to solve all 3 of these issues:
|
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.
There was a problem hiding this comment.
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
$itemsto use Form API-populated field values via an#after_buildcallback - Removed the
buildRankingPreview()method that built previews from$itemsin the wrong order - Added
afterBuildRebuildPreview()static method that builds previews from form field#valueproperties after the Form API has processed them
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…vior Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
- 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.
There was a problem hiding this comment.
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.
AZRankingComponentBuilder becomes the single source of truth mapping ranking item values to az_quickstart:ranking/ranking-image render arrays, shared by AZRankingDefaultFormatter and AZRankingWidget's live edit-form preview - previously the widget preview still rendered through the legacy #theme => 'az_ranking' template/hook_theme path (az-ranking.html.twig, az_ranking_theme(), plus its own now-dead az-ranking.css/az-ranking-image.css/az-ranking-focal-point-calc.js), duplicating the formatter's class-mapping logic and free to drift out of sync with what actually publishes. Both callers now build a plain values array (AZRankingComponentBuilder::extractItemValues()) instead of passing an AZRankingItem directly, since the widget's preview needs to build that same array from Form API values instead of a field item (see below) - keeping the builder item-agnostic is what lets it work for both. Also fixes az_quickstart#5156: after drag-and-drop reordering a paragraph's ranking items, clicking "Update Preview"/"Add Another Item"/"Remove" could leave previews showing stale data for the wrong row. Root cause: the preview was built from $items[$delta] (stored array order), while its sibling text/select fields are repopulated by the Form API from #value (always correct for the current row, since that's tree-position-based, not stored-order-based). Fixed the way az_quickstart/az_quickstart#5309 fixed it upstream: build the preview from the same Form API-populated #value the fields use, instead of the item, via a new custom Form API element (AZRankingItemElement) whose #process builds the fields and #after_build rebuilds the preview once its siblings have resolved - a real, reusable Element plugin instead of #after_build glue bolted onto Field API's own per-delta wrapper, so the preview keeps direct access to its sibling fields (an element scoped to the preview alone would lose that, since #after_build only sees its own descendants). Also drops the old original_deltas widget- state remap, which #5309 found actively breaks reorder rather than protecting it - table-drag already moves whole rows (fields + preview together) client-side, so no server-side delta remapping is needed. Verified via a real Drupal form-build cycle (\Drupal::formBuilder() ->doBuildForm()) against real paragraph data, not just isolated calls: confirmed #process and #after_build both fire in the correct order and the resulting preview matches the real stored values exactly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QZ6mWfeVEr5qdPLXAEmtqP
|
A better version of this is implemented in #5834 , taking into consideration Troy's recommendation to use a custom form api element for Rankings instead of using an #after-build callback (this PR). |
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 bothdetails(form elements like textfields and selects) andpreview_wrapper(that renders the preview for the ranking item). The KEY ISSUE is: afterformElement()returns, Drupal's Form API treats these two children differently:detailscontains standard form elements (#type=>textfield,select, etc.). The Form API automatically populates their#valuefrom 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_wrapperis a plain render array (#theme=>az_ranking). The Form API does not touch render arrays — whatever values are set informElement()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.
#after_buildcallback:#valuesources as the form fields. We use this to replace the current function that builds from$item(buildRankingPreview()).#valuestructure differs from simple form elements. We just read from$form_state->getUserInput()to ensure it matches the same delta order as text fields.Release notes
Related issues
How to test
Make sure
az_paragraphs_rankingsis enabledTypes of changes
Arizona Quickstart (install profile, custom modules, custom theme)
Drupal core
Drupal contrib projects
Checklist