forms: x-blankAs "empty" -- a string cleared in an edit form submits "" instead of being omitted - #824
Merged
Conversation
…"" instead of being omitted
DynamicForm omits a blank control from the payload. For an edit form
prefilled from a stored record whose model reads an absent
std::optional<std::string> as "leave unchanged" and "" as "clear", that
made a prefilled string impossible to clear: deleting the text sent
nothing, and the stored value survived.
A string property carrying "x-blankAs": "empty" now submits "" when its
control is blank -- once the field is engaged since the last prefill or
reset: prefilled with a string ("" included), or non-blank at any
revalidate() since, whichever path wrote it (a control, setFieldValue, a
slot's setValue). A field never prefilled and never typed into is still
omitted, and a stored null does not engage it. `required` is unchanged: a
required field left blank is still unfilled. The key is read only for kind
"string" (nullable spellings included); every other kind ignores it.
C++: FieldMeta gains `BlankAs blankAs{BlankAs::Omit}` (+ withBlankAs()),
emitted as "x-blankAs": "empty" on a std::string /
std::optional<std::string> member only. Presentation only; the wire is
unchanged.
tst_DynamicFormBlankAs.qml (12 cases) asserts submitted bodies: never
emitting "" reddens 4, ignoring engagement reddens 6.
test_forms_blank_as.cpp pins the emission. forms_qml_logic: 409 passed,
[forms] C++ cases all green on MSVC / Qt 6.11.1.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What / why
DynamicForm leaves a blank control out of the payload. Consider an edit form prefilled from a stored record, where the model reads an absent
std::optional<std::string>as "leave unchanged" and""as "clear". In that form a prefilled string cannot be cleared: when the user deletes the text, the member is omitted and the stored value stays.Contract
Schema key: property-level
"x-blankAs": "empty", read with the same dual-read as the other property keys. The descriptor exposes it asblankAsEmpty. It is only read for fields of kindstring, including["string","null"]and the nullableanyOfspelling.What a blank control submits, by field state since the last
prefill/resetFields:""included"field": ""setFieldValue, slotsetValue), then cleared"field": ""nulldoes not count as prefilled.Other rules:
FieldMetagainsBlankAs blankAs{BlankAs::Omit}(enum class BlankAs { Omit, Empty }) pluswithBlankAs(). It emits"x-blankAs": "empty", but only on astd::string/std::optional<std::string>member.Tests
src/qt/forms/tests/tst_DynamicFormBlankAs.qml, 12 cases, all asserting the submitted body. It covers:""""""round-trips; a storednulldoes not engage the fieldsetValue("")behaves the sametests/test_forms_blank_as.cppchecks that the key is emitted on string members, and not by default or on adouble, and that the wire is unchanged.Mutation checks (actually run):
""""Local results (MSVC / Qt 6.11.1, offscreen):
forms_qml_logic: 409 passed, 0 failedmorph_tests "[forms]": all passedIndependent of #822 / #823.
🤖 Generated with Claude Code