Skip to content

Fix: Unable to custom reorder repeatable date/time values (#7471)#7486

Closed
faisalahammad wants to merge 1 commit intopods-framework:release/3.3.5from
faisalahammad:fix/7471-repeatable-date-reorder
Closed

Fix: Unable to custom reorder repeatable date/time values (#7471)#7486
faisalahammad wants to merge 1 commit intopods-framework:release/3.3.5from
faisalahammad:fix/7471-repeatable-date-reorder

Conversation

@faisalahammad
Copy link
Contributor

@faisalahammad faisalahammad commented Jan 30, 2026

Summary

Fixes the inability to reorder repeatable date/time field values via drag-and-drop in the admin UI.

Closes #7471


🔍 Root Cause Analysis

When users drag-and-drop to reorder repeatable field values, the following chain of events occurs:

  1. handleDragEnd() in RepeatableFieldList calls arrayMove() to reorder the valuesArray
  2. setFullValue() updates the parent state, triggering a re-render
  3. Each SubfieldWrapper receives a new value prop at its position

Why It Didn't Work for Date/Time Fields

Problem 1: Stale Internal State

Fields like DateTime, Currency, and NumberField maintain internal React state for formatted display values:

// DateTime component - internal state initialized once
const [ localStringValue, setLocalStringValue ] = useState(
    () => formatMomentObject(moment(value, [...]), value)
);
const [ localMomentValue, setLocalMomentValue ] = useState(
    () => formatMomentObject(moment(value, [...]), value)
);

The useState initializer function only runs on first render. When the value prop changed after a drag-drop reorder, the internal state remained stale because there was no mechanism to sync it.

Problem 2: Position-Based React Keys

// Old key - based only on position index
key={ `${ fieldConfig.name }-${ index }` }

When items reorder:

  • Before: ["2024-01-01", "2024-02-02"] → Keys: ["field-0", "field-1"]
  • After swap: ["2024-02-02", "2024-01-01"] → Keys: ["field-0", "field-1"] (unchanged!)

React sees the same keys and reuses the same component instances, just passing new props. For simple text inputs this works fine (they directly use value prop), but for DateTime the stale internal state causes the display to "snap back" to old values.


✅ Solution

Fix 1: Added useEffect to Sync State with Props

Before:

// No sync mechanism - internal state becomes stale on prop changes
const [ localStringValue, setLocalStringValue ] = useState(() => {...});
const [ localMomentValue, setLocalMomentValue ] = useState(() => {...});

After:

const [ localStringValue, setLocalStringValue ] = useState(() => {...});
const [ localMomentValue, setLocalMomentValue ] = useState(() => {...});

// NEW: Sync local state with external value changes (e.g., after drag-and-drop reorder)
useEffect( () => {
    const isCurrentValueEmpty = [ '0000-00-00', '0000-00-00 00:00:00', '' ].includes( value );

    if ( isCurrentValueEmpty ) {
        setLocalStringValue( '' );
        setLocalMomentValue( '' );
    } else {
        const momentParsed = moment( value, [ getDBFormat(), getFullFormat() ] );
        setLocalStringValue( formatMomentObject( momentParsed, value ) );
        setLocalMomentValue( momentParsed );
    }
}, [ value ] );

Fix 2: Changed React Key to Include Value

Before:

key={ `${ fieldConfig.name }-${ index }` }

After:

key={ `${ fieldConfig.name }-${ JSON.stringify( valueItem ) }-${ index }` }

By including the value in the key, React treats components as different when their values change positions, forcing a proper remount with fresh state initialization.


📁 Files Changed

File Change
ui/js/dfv/src/components/field-wrapper/repeatable-field-list.js Value-based key for proper React reconciliation
ui/js/dfv/src/fields/datetime/index.js Added useEffect to sync internal state
ui/js/dfv/src/fields/currency/index.js Added useEffect to sync internal state
ui/js/dfv/src/fields/number-field/index.js Added useEffect to sync internal state

🧪 Testing

Automated

  • All 512 Jest tests pass ✅
  • RepeatableFieldList tests pass ✅
  • DateTime, Currency, NumberField tests pass ✅

Manual Testing Steps

  1. Create a Pod with a repeatable Date/Time field
  2. Add 3+ date values
  3. Drag and drop to reorder
  4. ✅ Verify values stay in the new order (no snapping back)
  5. Save and reload to confirm persistence

Also tested with repeatable Currency and Number fields.


📦 Test Build

pods-fix-7471.zip

Screen recording

https://videos.faisalahammad.com/recordings/c8bJrtegcX4p7bWJBOfH

…work#7471)

This commit fixes the drag-and-drop reordering functionality for repeatable
fields that use internal React state (DateTime, Currency, NumberField).

Root Cause:
-----------
When users drag-and-drop to reorder repeatable field values, the parent
component calls arrayMove() to reorder the values array. However, field
components like DateTime maintain internal state (localStringValue,
localMomentValue) that was initialized once via useState() and never
updated when the external 'value' prop changed.

Additionally, React was reusing the same component instances because the
key prop was based solely on position index (fieldConfig.name-index),
causing stale internal state to persist even as values swapped positions.

Solution:
---------
1. Added useEffect hooks to sync internal state with external value prop
   changes in DateTime, Currency, and NumberField components.

2. Changed the React key in RepeatableFieldList to include the actual
   value (fieldConfig.name-JSON.stringify(valueItem)-index), forcing
   React to remount components when values change positions.

Affected Files:
- ui/js/dfv/src/components/field-wrapper/repeatable-field-list.js
- ui/js/dfv/src/fields/datetime/index.js
- ui/js/dfv/src/fields/currency/index.js
- ui/js/dfv/src/fields/number-field/index.js

Fixes pods-framework#7471
@what-the-diff
Copy link

what-the-diff bot commented Jan 30, 2026

PR Summary

  • Software Version Update
    The software version in pods-dfv.min.asset.json has been updated to a new value "1c787679135b0a07425a". This change ensures that the system stays up-to-date with the latest improvements.

  • Enhanced Key Generation
    The key generation process in repeatable-field-list.js has been modified. Now, it includes the serialized value of the item, which enhances uniqueness. This change will reduce possible conflicts and improve overall system reliability.

  • State Synchronization Added in Currency Handling
    Added a new feature in currency/index.js that keeps the local state in sync with changes happening externally after reordering elements through drag-and-drop. This change enhances usability and ensures accurate reflection of value ranks.

  • Automated Updates in Date and Time Processing
    An automated process has been added to datetime/index.js that updates the local string and moment value based on changes in external value. This change reduces manual intervention, thereby increasing efficiency.

  • Automated Number Field Updates
    An automated process in number-field/index.js updates the formatted value when the external value changes. This effectively ensures consistency between internal and external numerical values, leading to accurate data representations.

@sc0ttkclark sc0ttkclark changed the base branch from main to release/3.3.5 February 22, 2026 04:25
@sc0ttkclark
Copy link
Member

Needs to be rebased before it can be merged but the code looks good

@sc0ttkclark
Copy link
Member

@faisalahammad I recommend giving your fork / PRs permissions to the upstream maintainer to edit. That would let me rebase your PRs and get them prepared for merge.

@sc0ttkclark
Copy link
Member

Merged manually via 5ae56d4

@pdclark pdclark mentioned this pull request Mar 3, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Unable to custom reorder repeatable date values

2 participants