Эта страница ещё не переведена, поэтому показана на английском. Помогите с переводом

Enable submit when the form is valid

Toss-up async

Requirement

A signup form has two fields. The email field emits nam, then nam@fx.dev; the password field emits hunter2, then box-belt-42 — at fixed interleaved offsets. After every change once both fields have emitted, re-evaluate the pair of latest values (valid = email contains @, password ≥ 8 chars) and print the combined state — three lines from the four field events, because the first change lands before the password has spoken; finish with the submit button's final state. Both versions must print the lines shown under Expected output.

Expected output
email=nam password=hunter2 -> disabled
email=nam@fx.dev password=hunter2 -> disabled
email=nam@fx.dev password=box-belt-42 -> enabled
submit: enabled

Side by side

RxDart

FxDart

Why they differ

They don't. Latest-value-per-source state is the defining combinator of the push model, and both panels declare it in one line: hold the newest value from each field, wait until both have spoken, re-emit the pair on every change from either side. RxDart writes Rx.combineLatest2(emails(), passwords(), ...); fxdart writes fxEvents(emails()).combineLatest(passwords(), ...). Same waiting rule, same re-emission on either side, same close-when-both-close — the tagged-merge-and-fold the fxdart panel used to hand-roll is gone.

fxdart's events layer absorbs the Rx approach for exactly this kind of job: a deliberate wrapper chain over plain Streams — not an extension, so it coexists with rxdart or any other stream library without conflicts — carrying the latest-value combinators the pull pipelines cannot have. One honest caveat stands: RxDart's operator catalog remains far larger than fxdart's events layer. When the combined form state should drive typed, demand-driven work — a validated submit call with typed errors, say — .pull() crosses from the live pairs into the FxAsync pipeline.

Benchmark

No benchmark for this example. This operator is defined by elapsed time, not by work done: both sides wait out the same windows, so a bar would be measuring Dart's timers rather than either library. Shrinking the windows does not help either — how many values a burst produces would then depend on how fast the machine is, and the two sides could no longer be checked against an identical result. The examples built on timing operators are left unmeasured for that reason; the ones whose delays merely stand in for I/O are benchmarked with those delays set to zero.