#Forms#State

Interdependent Inputs With Rollback

Four fields that constrain each other, where an invalid edit rolls back to its parent value instead of being clamped.

By Pratik RaiHard

Four inputs — a number, a select, a range and a number — each of which must not exceed the one to its right. An edit that would break the chain does not get clamped or merely flagged: it rolls back to the value of its parent.

This exposes shaky state modelling faster than almost anything else on the list. Four fields with pairwise constraints invite four ad-hoc if statements, and the result is correct for the case the candidate had in mind and wrong for the others.

Naming the relationship as data fixes it. A map from each field to its parent means one rule covers all of them — including the fact that the last field is unbounded, which falls out of it having no parent rather than needing its own branch.

The direction most people miss is downward. Rolling back handles raising a field past its parent. It does nothing about dragging the last field down below the one before it, which breaks the same chain from the other end. Walking left from the edited field and pulling anything now too large down with it covers that in a few lines.

The guard that matters most looks like a formality: check Number.isFinite before comparing anything. Number("abc") is NaN, and every comparison against NaN is false — so a corrupt value passes every bound check, lands in state, and the form silently stops enforcing anything at all.

The range input is in the requirements deliberately, because it fires continuously while dragged and any implementation that fights the user shows up immediately.

Goal: Keep four interdependent fields valid in both directions, rolling back corrupt edits.

Source

Frequently asked questions

How do you manage fields that constrain each other?
Name the relationship as data — a map from each field to the one that bounds it — so a single rule covers every field instead of one hand-written comparison per pair.
What is the difference between rolling back and clamping?
Clamping keeps the edit and limits it to the nearest legal value. Rolling back discards the edit and restores the parent's value. Both keep the data valid, and only one may be what was asked for — so check.
Why do constraints need enforcing in both directions?
Raising a field can break the constraint against the field above it, and lowering one can break it against the fields below. Handling only the first leaves the chain breakable from the other end.
Why check Number.isFinite before comparing?
Because `Number("abc")` is `NaN` and every comparison with `NaN` is false, so a corrupt value passes every bound check, lands in state, and the form silently stops enforcing anything.

Related Challenges

Continue learning with these related challenges

View All
React

Sequential Progress Bars

Clicking Add appends a progress bar, and the bars fill strictly one at a time. A queueing problem disguised as an animation.

React · JavaScriptPratik Rai ·

React

File Explorer

Build a nested folder tree from nothing — expand, collapse, and add files and folders at any depth.

React · JavaScriptPratik Rai ·

React

To-Do With Filter Tabs

A task list with In progress, Completed and Deleted tabs — where deletion cannot mean removal.

React · JavaScriptPratik Rai ·