customfields: leave never-set numeric fields unset instead of NaN, clear reused widgets - #269
customfields: leave never-set numeric fields unset instead of NaN, clear reused widgets#269asig2016 wants to merge 2 commits into
Conversation
…without a stored value et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Normalize null to "" for numeric fields at the producer. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MFMF3JZxodnWwbNqurKN7s
…without a stored value et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Normalize null to "" for numeric fields at the producer. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MFMF3JZxodnWwbNqurKN7s
|
The new Et2Customfields widget is a work-in-progress, and maybe should not be doing that since it takes your earlier approach of setting null -> "" and does it for any numeric customfield. |
…without a stored value et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Normalize null to "" for numeric fields at the producer. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MFMF3JZxodnWwbNqurKN7s
…ear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Replaces the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…abels Legacy-widget drop-in gaps that app code still relies on when it addresses the customfields widget as one input (the same way et2_customfields_list behaved): - set_value() - getValue(), answering with the collected #name => value object only for the legacy DEFAULT_ID "custom_fields" and null otherwise, so etemplate2 submission stays with the individual child widgets - snapshot-based isDirty()/resetDirty(); resetDirty() snapshots only after the queued Lit re-render and the child widgets settle - a synchronous snapshot describes the previously shown fields and makes every set_value() look like unsaved changes Layout: cap the label column at fit-content(45%) so a long label wraps instead of squeezing the value input to nothing in narrow panes, and drop the label attr from date/date-time field widgets - the container renders the label column itself, so date fields showed their label twice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MFMF3JZxodnWwbNqurKN7s
538e22c to
f44035d
Compare
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
If you need these fixes now, I'd merge this without the recently added values chunk. |
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
… clear reused widgets et2_customfields_list.set_value() coerces missing (and falsy) stored values to null before pushing them into the per-field child widgets. For float/int custom fields the child is an et2-number, whose value setter runs the value through parseFloat: parseFloat(null) parses the string "null" and yields NaN, so the input displays the literal text "NaN" and the subsequent save fails the pattern validation. Per review on upstream PR EGroupware#269: don't turn "not yet set" into "set as empty" - a pristine widget is left completely untouched on null. A plain skip is not enough though: preview / CRM-style views reuse one widget instance across records via set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. So null is skipped only while the widget shows nothing, and clears it otherwise. The switch matches "number" as well, because _setup_float/_setup_int rewrite field.type on the shared field object during row creation. Upstream PR EGroupware#269, replacing the Et2Number-side approach of PR EGroupware#268. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 581153c)
Problem
Float and integer custom fields without a stored value render the literal text "NaN" in edit forms, and saving the entry then fails the
/^-?[0-9]*[,.]?[0-9]*$/pattern validation — the record cannot be saved at all while such a field is visible.Cause
et2_customfields_list.set_value()coerces missing (and falsy) stored values tonullbefore pushing them into the per-field child widgets:For float/int custom fields the child is an
et2-number, whose value setter passes the value throughparseFloat."" + nullis"null", so it slips past the empty-value guard, andparseFloat(null)parses the string"null"→NaN. Withprecisionset,NaN.toFixed(precision)produces the string"NaN", which is written into the input.Fix
Per review feedback:
nullis no longer pushed into the child widget at all — a pristine widget is left completely untouched, so "not yet set" stays unset instead of becoming "set as empty".A plain skip is not quite enough, though: preview / CRM-style views reuse one widget instance across records via
set_value(), and skipping there would leave the previous record's number displayed on a record where the field is unset. Sonullis skipped only while the widget currently shows nothing, and clears it otherwise.The switch matches
"number"as well as"float"/"int", because_setup_float/_setup_intrewritefield.typeon the shared field object during row creation —"number"is the typeset_value()actually sees at runtime.The newer
Et2Customfieldsweb component is not affected: its_fieldValue()already maps missing/null values to""via nullish coalescing.Relation to the previous approach (#268)
#268 fixed the same symptom inside
Et2Numberitself, by normalizingnull/undefined/NaNin its value setter. As @nathangray pointed out there,nullhas the special meaning "not set" for form submission (null values are omitted byetemplate2.getValues()), so changing how the shared widget handlesnullis riskier than it looks. This PR fixes the producer instead, sonullnever reaches the widget, and leavesEt2Numberuntouched. I'd suggest this one replaces #268.Second commit: Et2Customfields legacy input API + label layout
Rounds out
Et2Customfieldsas a drop-in for the legacy widget and fixes two layout problems that surface in narrow panes:Legacy input API. App code that addresses the customfields widget as a single input (the way
et2_customfields_listallowed) needs:set_value()getValue()— answers with the collected#name => valueobject only for the legacyDEFAULT_IDcustom_fieldsandnullotherwise, matching the legacy widget, so etemplate2 submission stays with the individual#namechild widgetsisDirty()/resetDirty()—resetDirty()snapshots only after the queued Lit re-render (and the child widgets) settle; a synchronous snapshot describes the previously shown fields and makes everyset_value()look like unsaved changesLayout. The label column was
max-content, so one long label squeezes every value input to a sliver in a narrow pane; it is nowfit-content(45%), making long labels wrap instead. Anddate/date-timefield widgets kept theirlabelattr, so they rendered the label a second time above the input — the container already renders the label column, the attr is now dropped (filters re-set it after the switch, they have no label column).🤖 Generated with Claude Code
https://claude.ai/code/session_01MFMF3JZxodnWwbNqurKN7s