From 4c407f3db3fdacb45bf59a50a7c4c38e8ad695a4 Mon Sep 17 00:00:00 2001 From: Mert Karaca Date: Fri, 13 Mar 2026 00:47:06 +0100 Subject: [PATCH 1/8] Add a section detailing formatters --- .../pluggable-widgets-client-apis/_index.md | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md index a17df8bc2a0..1c8ef40e133 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -161,6 +161,79 @@ In practice, many client components present values as nicely formatted strings w There is a way to use more the convenient `displayValue` and `setTextValue` while retaining control over the format. A component can use a `setFormatter` method passing a formatter object: an object with `format` and `parse` methods. The Mendix Platform provides a convenient way of creating such objects for simple cases. An existing formatter exposed using a `EditableValue.formatter` field can be modified using its `withConfig` method. For complex cases formatters still can be created manually. A formatter can be reset back to default settings by calling `setFormatter(undefined)`. +#### Formatter Details {#formatter-details} + +The `formatter` field on `EditableValue` is defined as follows: + +```ts +type ParseResult = { valid: true; value: T } | { valid: false }; + +interface SimpleFormatter { + format(value: T | undefined): string; + parse(value: string): ParseResult; +} +} +``` + +Yu can supply a fully custom formatter using `setFormatter`. The object must implement `format` and `parse`: + +```ts +myDecimalAttribute.setFormatter({ + format(value: Big | undefined): string { + return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; + }, + parse(text: string): ParseResult { + const num = Number(text.replace(/[$,]/g, "")); + return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; + } +}); + +``` + +Call `setFormatter(undefined)` to reset to the platform default. + +**Date/DateTime** attributes have additional capabilities thanks to `DateTimeFormatter` which extends `SimpleFormatter`: + +```ts +interface DateTimeFormatter { + type: "datetime"; + format(value: Date | undefined): string; + parse(value: string): { valid: true; value: Date } | { valid: false }; + withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; + getFormatPlaceholder(): string; + config: DateTimeFormatterConfig; +} +``` + +You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly: + +```ts +if (myAttribute.formatter.type === "datetime") { + // Date-specific formatting logic +} else { + // String, number, enum, or boolean formatting logic +} +``` + +The following example formats a date attribute using a custom month-year pattern: + +```ts +if (myDateAttribute.formatter.type === "datetime") { + const customFormatter = myDateAttribute.formatter.withConfig({ + type: "custom", + pattern: "MMMM YYYY" + }); + const formatted = customFormatter.format(myDateAttribute.value); // e.g. "March 2026" +} +``` + +For enumeration and boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: + +```ts +// myEnumAttribute is an EditableValue +const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress" +``` + The optional field `universe` is used to indicate the set of all possible values that can be passed to a `setValue` if a set is limited. Currently, `universe` is provided only when the edited value is of the Boolean or enumeration [types](/refguide/attributes/#type). ### ModifiableValue {#modifiable-value} From 4d8eaf09ec88611b89fac236dfdc7babd51088da Mon Sep 17 00:00:00 2001 From: ConnorLand Date: Fri, 13 Mar 2026 13:46:53 +0100 Subject: [PATCH 2/8] Update _index.md --- .../pluggable-widgets-client-apis/_index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 1c8ef40e133..46223d073bd 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -175,7 +175,7 @@ interface SimpleFormatter { } ``` -Yu can supply a fully custom formatter using `setFormatter`. The object must implement `format` and `parse`: +You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`): ```ts myDecimalAttribute.setFormatter({ @@ -190,9 +190,9 @@ myDecimalAttribute.setFormatter({ ``` -Call `setFormatter(undefined)` to reset to the platform default. +Call `setFormatter(undefined)` to reset the formatter to the platform default. -**Date/DateTime** attributes have additional capabilities thanks to `DateTimeFormatter` which extends `SimpleFormatter`: +**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter`: ```ts interface DateTimeFormatter { @@ -227,7 +227,7 @@ if (myDateAttribute.formatter.type === "datetime") { } ``` -For enumeration and boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: +For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: ```ts // myEnumAttribute is an EditableValue From 9d116def4736105a14cda3d4148c013a080641a4 Mon Sep 17 00:00:00 2001 From: ConnorLand Date: Fri, 13 Mar 2026 13:53:49 +0100 Subject: [PATCH 3/8] Move paragraph to be back under Editable Value --- .../pluggable-widgets/pluggable-widgets-client-apis/_index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 46223d073bd..3f004f50769 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -161,6 +161,8 @@ In practice, many client components present values as nicely formatted strings w There is a way to use more the convenient `displayValue` and `setTextValue` while retaining control over the format. A component can use a `setFormatter` method passing a formatter object: an object with `format` and `parse` methods. The Mendix Platform provides a convenient way of creating such objects for simple cases. An existing formatter exposed using a `EditableValue.formatter` field can be modified using its `withConfig` method. For complex cases formatters still can be created manually. A formatter can be reset back to default settings by calling `setFormatter(undefined)`. +The optional field `universe` is used to indicate the set of all possible values that can be passed to a `setValue` if a set is limited. Currently, `universe` is provided only when the edited value is of the Boolean or enumeration [types](/refguide/attributes/#type). + #### Formatter Details {#formatter-details} The `formatter` field on `EditableValue` is defined as follows: @@ -234,8 +236,6 @@ For enumeration and Boolean attributes, `format` converts the raw value into a h const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress" ``` -The optional field `universe` is used to indicate the set of all possible values that can be passed to a `setValue` if a set is limited. Currently, `universe` is provided only when the edited value is of the Boolean or enumeration [types](/refguide/attributes/#type). - ### ModifiableValue {#modifiable-value} `ModifiableValue` is used to represent values that can be changed by a pluggable widget client component. It is passed only to [association properties](/apidocs-mxsdk/apidocs/pluggable-widgets-property-types-10/#association), and is defined as follows: From 96cc32abca71e537af893411309335ffb608fa8c Mon Sep 17 00:00:00 2001 From: ConnorLand Date: Fri, 13 Mar 2026 13:55:57 +0100 Subject: [PATCH 4/8] Duplicate section to Mx9 and 10 --- .../pluggable-widgets-client-apis/_index.md | 73 +++++++++++++++++++ .../pluggable-widgets-client-apis-9/_index.md | 73 +++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md index fcb9e81228d..4ea9701999b 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -161,6 +161,79 @@ There is a way to use more the convenient `displayValue` and `setTextValue` whi The optional field `universe` is used to indicate the set of all possible values that can be passed to a `setValue` if a set is limited. Currently, `universe` is provided only when the edited value is of the Boolean or enumeration [types](/refguide/attributes/#type). +#### Formatter Details {#formatter-details} + +The `formatter` field on `EditableValue` is defined as follows: + +```ts +type ParseResult = { valid: true; value: T } | { valid: false }; + +interface SimpleFormatter { + format(value: T | undefined): string; + parse(value: string): ParseResult; +} +} +``` + +You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`): + +```ts +myDecimalAttribute.setFormatter({ + format(value: Big | undefined): string { + return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; + }, + parse(text: string): ParseResult { + const num = Number(text.replace(/[$,]/g, "")); + return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; + } +}); + +``` + +Call `setFormatter(undefined)` to reset the formatter to the platform default. + +**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter`: + +```ts +interface DateTimeFormatter { + type: "datetime"; + format(value: Date | undefined): string; + parse(value: string): { valid: true; value: Date } | { valid: false }; + withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; + getFormatPlaceholder(): string; + config: DateTimeFormatterConfig; +} +``` + +You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly: + +```ts +if (myAttribute.formatter.type === "datetime") { + // Date-specific formatting logic +} else { + // String, number, enum, or boolean formatting logic +} +``` + +The following example formats a date attribute using a custom month-year pattern: + +```ts +if (myDateAttribute.formatter.type === "datetime") { + const customFormatter = myDateAttribute.formatter.withConfig({ + type: "custom", + pattern: "MMMM YYYY" + }); + const formatted = customFormatter.format(myDateAttribute.value); // e.g. "March 2026" +} +``` + +For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: + +```ts +// myEnumAttribute is an EditableValue +const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress" +``` + ### EditableFileValue {#editable-file-value} `EditableFileValue` is used to represent file values, that can be changed by a pluggable widget client component and is passed only to [file](/apidocs-mxsdk/apidocs/pluggable-widgets-property-types/#file). It is defined as follows: diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md index cb5e20b8e4f..43aaf0e9d38 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md @@ -133,6 +133,79 @@ There is a way to use more the convenient `displayValue` and `setTextValue` whi The optional field `universe` is used to indicate the set of all possible values that can be passed to a `setValue` if a set is limited. Currently, `universe` is provided only when the edited attribute is of the Boolean or enumeration [types](/refguide9/attributes/#type). +#### Formatter Details {#formatter-details} + +The `formatter` field on `EditableValue` is defined as follows: + +```ts +type ParseResult = { valid: true; value: T } | { valid: false }; + +interface SimpleFormatter { + format(value: T | undefined): string; + parse(value: string): ParseResult; +} +} +``` + +You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`): + +```ts +myDecimalAttribute.setFormatter({ + format(value: Big | undefined): string { + return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; + }, + parse(text: string): ParseResult { + const num = Number(text.replace(/[$,]/g, "")); + return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; + } +}); + +``` + +Call `setFormatter(undefined)` to reset the formatter to the platform default. + +**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter`: + +```ts +interface DateTimeFormatter { + type: "datetime"; + format(value: Date | undefined): string; + parse(value: string): { valid: true; value: Date } | { valid: false }; + withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; + getFormatPlaceholder(): string; + config: DateTimeFormatterConfig; +} +``` + +You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly: + +```ts +if (myAttribute.formatter.type === "datetime") { + // Date-specific formatting logic +} else { + // String, number, enum, or boolean formatting logic +} +``` + +The following example formats a date attribute using a custom month-year pattern: + +```ts +if (myDateAttribute.formatter.type === "datetime") { + const customFormatter = myDateAttribute.formatter.withConfig({ + type: "custom", + pattern: "MMMM YYYY" + }); + const formatted = customFormatter.format(myDateAttribute.value); // e.g. "March 2026" +} +``` + +For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: + +```ts +// myEnumAttribute is an EditableValue +const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress" +``` + ### ModifiableValue {#modifiable-value} `ModifiableValue` is used to represent values that can be changed by a pluggable widget client component. It is passed only to [association properties](/apidocs-mxsdk/apidocs/pluggable-widgets-property-types-9/#association), and is defined as follows: From d4d48c03a7071f38b222e0c041ced4bd42ba399c Mon Sep 17 00:00:00 2001 From: Mert Karaca Date: Mon, 16 Mar 2026 10:51:04 +0100 Subject: [PATCH 5/8] Review: extend the information about built-in formatters --- .../pluggable-widgets-client-apis/_index.md | 130 ++++++++++++++---- 1 file changed, 100 insertions(+), 30 deletions(-) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 3f004f50769..131840f6b81 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -171,52 +171,53 @@ The `formatter` field on `EditableValue` is defined as follows: type ParseResult = { valid: true; value: T } | { valid: false }; interface SimpleFormatter { - format(value: T | undefined): string; - parse(value: string): ParseResult; -} + format(value: T | undefined): string; + parse(value: string): ParseResult; } ``` -You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`): +##### Built-in Formatter Types {#built-in-formatter-types} -```ts -myDecimalAttribute.setFormatter({ - format(value: Big | undefined): string { - return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; - }, - parse(text: string): ParseResult { - const num = Number(text.replace(/[$,]/g, "")); - return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; - } -}); +The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: +```ts +type ValueFormatter = + | (TypedFormatter & (NumberFormatter | DateTimeFormatter)) + | (SimpleFormatter & { readonly type?: never }); ``` -Call `setFormatter(undefined)` to reset the formatter to the platform default. - -**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter`: +Use the `type` property as a type guard to narrow to a specific built-in formatter before accessing its extra API: ```ts -interface DateTimeFormatter { - type: "datetime"; - format(value: Date | undefined): string; - parse(value: string): { valid: true; value: Date } | { valid: false }; - withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; - getFormatPlaceholder(): string; - config: DateTimeFormatterConfig; +if (myAttribute.formatter.type === "datetime") { + // DateTimeFormatter — has withConfig, getFormatPlaceholder +} else if (myAttribute.formatter.type === "number") { + // NumberFormatter — has withConfig +} else { + // Plain SimpleFormatter — string, enum, or boolean } ``` -You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly: +##### DateTimeFormatter + +**Date/DateTime** attributes receive a `DateTimeFormatter`, which extends `SimpleFormatter`: ```ts -if (myAttribute.formatter.type === "datetime") { - // Date-specific formatting logic -} else { - // String, number, enum, or boolean formatting logic +interface DateTimeFormatter extends SimpleFormatter { + readonly type: "datetime"; + readonly config: DateTimeFormatterConfig; + withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; + getFormatPlaceholder(): string | undefined; } ``` +The `withConfig` method returns a **new formatter** with a different date pattern while preserving the user's locale. It accepts a `DateTimeFormatterConfig` with the following options: + +* `{ type: "date" }` — platform default date format +* `{ type: "time" }` — platform default time format +* `{ type: "datetime" }` — platform default datetime format +* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) + The following example formats a date attribute using a custom month-year pattern: ```ts @@ -229,13 +230,82 @@ if (myDateAttribute.formatter.type === "datetime") { } ``` -For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: +`getFormatPlaceholder` returns a locale-appropriate placeholder string for the active date pattern, useful for input field `placeholder` attributes: + +```ts +const placeholder = myDateAttribute.formatter.type === "datetime" + ? myDateAttribute.formatter.getFormatPlaceholder() + : undefined; +``` + +##### NumberFormatter + +**Decimal**, **Integer**, and **Long** attributes receive a `NumberFormatter`, which extends `SimpleFormatter`: + +```ts +interface NumberFormatter extends SimpleFormatter { + readonly type: "number"; + readonly config: NumberFormatterConfig; + withConfig(config: NumberFormatterConfig): NumberFormatter; +} +``` + +`NumberFormatterConfig` has the following options: + +```ts +interface NumberFormatterConfig { + readonly groupDigits: boolean; // e.g. 1,000,000 + readonly decimalPrecision?: number; +} +``` + +The following example disables the thousands separator and fixes the output to four decimal places: + +```ts +if (myNumberAttribute.formatter.type === "number") { + const customFormatter = myNumberAttribute.formatter.withConfig({ + groupDigits: false, + decimalPrecision: 4 + }); + const formatted = customFormatter.format(myNumberAttribute.value); // e.g. "1234.5600" +} +``` + +##### Plain SimpleFormatter + +For **string**, **enumeration**, and **Boolean** attributes the platform provides a plain `SimpleFormatter` without a `type` property. These formatters convert raw values to human-readable captions (for example, enum captions configured in Studio Pro) and parse text input back to the typed value. They do **not** have `withConfig` or `getFormatPlaceholder`: ```ts // myEnumAttribute is an EditableValue const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress" ``` +##### Custom Formatters via setFormatter + +You can supply a fully custom formatter for any attribute type using `setFormatter`. The object must implement `format` and `parse`: + +```ts +myDecimalAttribute.setFormatter({ + format(value: Big | undefined): string { + return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; + }, + parse(text: string): { valid: true; value: Big } | { valid: false } { + const num = Number(text.replace(/[$,]/g, "")); + return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; + } +}); +``` + +Call `setFormatter(undefined)` to reset the formatter to the platform default. + +##### Quick Reference + +| Formatter type | `type` value | `withConfig` | `getFormatPlaceholder` | Applies to | +|---|---|---|---|---| +| `DateTimeFormatter` | `"datetime"` | ✅ `DateTimeFormatterConfig` | ✅ | `Date` | +| `NumberFormatter` | `"number"` | ✅ `NumberFormatterConfig` | ❌ | `Big` (Decimal, Integer, Long) | +| `SimpleFormatter` | `undefined` | ❌ | ❌ | `string`, `boolean`, Enum | + ### ModifiableValue {#modifiable-value} `ModifiableValue` is used to represent values that can be changed by a pluggable widget client component. It is passed only to [association properties](/apidocs-mxsdk/apidocs/pluggable-widgets-property-types-10/#association), and is defined as follows: From 6794092aa04239b1931007b0fa0e618d755fa020 Mon Sep 17 00:00:00 2001 From: Mert Karaca Date: Mon, 16 Mar 2026 20:46:16 +0100 Subject: [PATCH 6/8] Backport the review changes to version 9 and 10 --- .../pluggable-widgets-client-apis/_index.md | 130 ++++++++++++++---- .../pluggable-widgets-client-apis-9/_index.md | 130 ++++++++++++++---- 2 files changed, 200 insertions(+), 60 deletions(-) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 4ea9701999b..951da56e30f 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -169,52 +169,53 @@ The `formatter` field on `EditableValue` is defined as follows: type ParseResult = { valid: true; value: T } | { valid: false }; interface SimpleFormatter { - format(value: T | undefined): string; - parse(value: string): ParseResult; -} + format(value: T | undefined): string; + parse(value: string): ParseResult; } ``` -You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`): +##### Built-in Formatter Types {#built-in-formatter-types} -```ts -myDecimalAttribute.setFormatter({ - format(value: Big | undefined): string { - return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; - }, - parse(text: string): ParseResult { - const num = Number(text.replace(/[$,]/g, "")); - return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; - } -}); +The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: +```ts +type ValueFormatter = + | (TypedFormatter & (NumberFormatter | DateTimeFormatter)) + | (SimpleFormatter & { readonly type?: never }); ``` -Call `setFormatter(undefined)` to reset the formatter to the platform default. - -**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter`: +Use the `type` property as a type guard to narrow to a specific built-in formatter before accessing its extra API: ```ts -interface DateTimeFormatter { - type: "datetime"; - format(value: Date | undefined): string; - parse(value: string): { valid: true; value: Date } | { valid: false }; - withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; - getFormatPlaceholder(): string; - config: DateTimeFormatterConfig; +if (myAttribute.formatter.type === "datetime") { + // DateTimeFormatter — has withConfig, getFormatPlaceholder +} else if (myAttribute.formatter.type === "number") { + // NumberFormatter — has withConfig +} else { + // Plain SimpleFormatter — string, enum, or boolean } ``` -You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly: +##### DateTimeFormatter + +**Date/DateTime** attributes receive a `DateTimeFormatter`, which extends `SimpleFormatter`: ```ts -if (myAttribute.formatter.type === "datetime") { - // Date-specific formatting logic -} else { - // String, number, enum, or boolean formatting logic +interface DateTimeFormatter extends SimpleFormatter { + readonly type: "datetime"; + readonly config: DateTimeFormatterConfig; + withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; + getFormatPlaceholder(): string | undefined; } ``` +The `withConfig` method returns a **new formatter** with a different date pattern while preserving the user's locale. It accepts a `DateTimeFormatterConfig` with the following options: + +* `{ type: "date" }` — platform default date format +* `{ type: "time" }` — platform default time format +* `{ type: "datetime" }` — platform default datetime format +* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) + The following example formats a date attribute using a custom month-year pattern: ```ts @@ -227,13 +228,82 @@ if (myDateAttribute.formatter.type === "datetime") { } ``` -For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: +`getFormatPlaceholder` returns a locale-appropriate placeholder string for the active date pattern, useful for input field `placeholder` attributes: + +```ts +const placeholder = myDateAttribute.formatter.type === "datetime" + ? myDateAttribute.formatter.getFormatPlaceholder() + : undefined; +``` + +##### NumberFormatter + +**Decimal**, **Integer**, and **Long** attributes receive a `NumberFormatter`, which extends `SimpleFormatter`: + +```ts +interface NumberFormatter extends SimpleFormatter { + readonly type: "number"; + readonly config: NumberFormatterConfig; + withConfig(config: NumberFormatterConfig): NumberFormatter; +} +``` + +`NumberFormatterConfig` has the following options: + +```ts +interface NumberFormatterConfig { + readonly groupDigits: boolean; // e.g. 1,000,000 + readonly decimalPrecision?: number; +} +``` + +The following example disables the thousands separator and fixes the output to four decimal places: + +```ts +if (myNumberAttribute.formatter.type === "number") { + const customFormatter = myNumberAttribute.formatter.withConfig({ + groupDigits: false, + decimalPrecision: 4 + }); + const formatted = customFormatter.format(myNumberAttribute.value); // e.g. "1234.5600" +} +``` + +##### Plain SimpleFormatter + +For **string**, **enumeration**, and **Boolean** attributes the platform provides a plain `SimpleFormatter` without a `type` property. These formatters convert raw values to human-readable captions (for example, enum captions configured in Studio Pro) and parse text input back to the typed value. They do **not** have `withConfig` or `getFormatPlaceholder`: ```ts // myEnumAttribute is an EditableValue const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress" ``` +##### Custom Formatters via setFormatter + +You can supply a fully custom formatter for any attribute type using `setFormatter`. The object must implement `format` and `parse`: + +```ts +myDecimalAttribute.setFormatter({ + format(value: Big | undefined): string { + return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; + }, + parse(text: string): { valid: true; value: Big } | { valid: false } { + const num = Number(text.replace(/[$,]/g, "")); + return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; + } +}); +``` + +Call `setFormatter(undefined)` to reset the formatter to the platform default. + +##### Quick Reference + +| Formatter type | `type` value | `withConfig` | `getFormatPlaceholder` | Applies to | +|---|---|---|---|---| +| `DateTimeFormatter` | `"datetime"` | ✅ `DateTimeFormatterConfig` | ✅ | `Date` | +| `NumberFormatter` | `"number"` | ✅ `NumberFormatterConfig` | ❌ | `Big` (Decimal, Integer, Long) | +| `SimpleFormatter` | `undefined` | ❌ | ❌ | `string`, `boolean`, Enum | + ### EditableFileValue {#editable-file-value} `EditableFileValue` is used to represent file values, that can be changed by a pluggable widget client component and is passed only to [file](/apidocs-mxsdk/apidocs/pluggable-widgets-property-types/#file). It is defined as follows: diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md index 43aaf0e9d38..5ddcfe6afb3 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md @@ -141,52 +141,53 @@ The `formatter` field on `EditableValue` is defined as follows: type ParseResult = { valid: true; value: T } | { valid: false }; interface SimpleFormatter { - format(value: T | undefined): string; - parse(value: string): ParseResult; -} + format(value: T | undefined): string; + parse(value: string): ParseResult; } ``` -You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`): +##### Built-in Formatter Types {#built-in-formatter-types} -```ts -myDecimalAttribute.setFormatter({ - format(value: Big | undefined): string { - return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; - }, - parse(text: string): ParseResult { - const num = Number(text.replace(/[$,]/g, "")); - return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; - } -}); +The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: +```ts +type ValueFormatter = + | (TypedFormatter & (NumberFormatter | DateTimeFormatter)) + | (SimpleFormatter & { readonly type?: never }); ``` -Call `setFormatter(undefined)` to reset the formatter to the platform default. - -**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter`: +Use the `type` property as a type guard to narrow to a specific built-in formatter before accessing its extra API: ```ts -interface DateTimeFormatter { - type: "datetime"; - format(value: Date | undefined): string; - parse(value: string): { valid: true; value: Date } | { valid: false }; - withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; - getFormatPlaceholder(): string; - config: DateTimeFormatterConfig; +if (myAttribute.formatter.type === "datetime") { + // DateTimeFormatter — has withConfig, getFormatPlaceholder +} else if (myAttribute.formatter.type === "number") { + // NumberFormatter — has withConfig +} else { + // Plain SimpleFormatter — string, enum, or boolean } ``` -You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly: +##### DateTimeFormatter + +**Date/DateTime** attributes receive a `DateTimeFormatter`, which extends `SimpleFormatter`: ```ts -if (myAttribute.formatter.type === "datetime") { - // Date-specific formatting logic -} else { - // String, number, enum, or boolean formatting logic +interface DateTimeFormatter extends SimpleFormatter { + readonly type: "datetime"; + readonly config: DateTimeFormatterConfig; + withConfig(config: DateTimeFormatterConfig): DateTimeFormatter; + getFormatPlaceholder(): string | undefined; } ``` +The `withConfig` method returns a **new formatter** with a different date pattern while preserving the user's locale. It accepts a `DateTimeFormatterConfig` with the following options: + +* `{ type: "date" }` — platform default date format +* `{ type: "time" }` — platform default time format +* `{ type: "datetime" }` — platform default datetime format +* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) + The following example formats a date attribute using a custom month-year pattern: ```ts @@ -199,13 +200,82 @@ if (myDateAttribute.formatter.type === "datetime") { } ``` -For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro: +`getFormatPlaceholder` returns a locale-appropriate placeholder string for the active date pattern, useful for input field `placeholder` attributes: + +```ts +const placeholder = myDateAttribute.formatter.type === "datetime" + ? myDateAttribute.formatter.getFormatPlaceholder() + : undefined; +``` + +##### NumberFormatter + +**Decimal**, **Integer**, and **Long** attributes receive a `NumberFormatter`, which extends `SimpleFormatter`: + +```ts +interface NumberFormatter extends SimpleFormatter { + readonly type: "number"; + readonly config: NumberFormatterConfig; + withConfig(config: NumberFormatterConfig): NumberFormatter; +} +``` + +`NumberFormatterConfig` has the following options: + +```ts +interface NumberFormatterConfig { + readonly groupDigits: boolean; // e.g. 1,000,000 + readonly decimalPrecision?: number; +} +``` + +The following example disables the thousands separator and fixes the output to four decimal places: + +```ts +if (myNumberAttribute.formatter.type === "number") { + const customFormatter = myNumberAttribute.formatter.withConfig({ + groupDigits: false, + decimalPrecision: 4 + }); + const formatted = customFormatter.format(myNumberAttribute.value); // e.g. "1234.5600" +} +``` + +##### Plain SimpleFormatter + +For **string**, **enumeration**, and **Boolean** attributes the platform provides a plain `SimpleFormatter` without a `type` property. These formatters convert raw values to human-readable captions (for example, enum captions configured in Studio Pro) and parse text input back to the typed value. They do **not** have `withConfig` or `getFormatPlaceholder`: ```ts // myEnumAttribute is an EditableValue const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress" ``` +##### Custom Formatters via setFormatter + +You can supply a fully custom formatter for any attribute type using `setFormatter`. The object must implement `format` and `parse`: + +```ts +myDecimalAttribute.setFormatter({ + format(value: Big | undefined): string { + return value !== undefined ? `$${Number(value).toFixed(2)}` : ""; + }, + parse(text: string): { valid: true; value: Big } | { valid: false } { + const num = Number(text.replace(/[$,]/g, "")); + return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) }; + } +}); +``` + +Call `setFormatter(undefined)` to reset the formatter to the platform default. + +##### Quick Reference + +| Formatter type | `type` value | `withConfig` | `getFormatPlaceholder` | Applies to | +|---|---|---|---|---| +| `DateTimeFormatter` | `"datetime"` | ✅ `DateTimeFormatterConfig` | ✅ | `Date` | +| `NumberFormatter` | `"number"` | ✅ `NumberFormatterConfig` | ❌ | `Big` (Decimal, Integer, Long) | +| `SimpleFormatter` | `undefined` | ❌ | ❌ | `string`, `boolean`, Enum | + ### ModifiableValue {#modifiable-value} `ModifiableValue` is used to represent values that can be changed by a pluggable widget client component. It is passed only to [association properties](/apidocs-mxsdk/apidocs/pluggable-widgets-property-types-9/#association), and is defined as follows: From 8ef533c784aea16a1994f21c3533ea3000ea8df3 Mon Sep 17 00:00:00 2001 From: ConnorLand Date: Wed, 18 Mar 2026 13:33:55 +0100 Subject: [PATCH 7/8] Remove dashes --- .../pluggable-widgets-client-apis/_index.md | 8 ++++---- .../pluggable-widgets-client-apis/_index.md | 8 ++++---- .../pluggable-widgets-client-apis-9/_index.md | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 131840f6b81..46f3ca052b7 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -213,10 +213,10 @@ interface DateTimeFormatter extends SimpleFormatter { The `withConfig` method returns a **new formatter** with a different date pattern while preserving the user's locale. It accepts a `DateTimeFormatterConfig` with the following options: -* `{ type: "date" }` — platform default date format -* `{ type: "time" }` — platform default time format -* `{ type: "datetime" }` — platform default datetime format -* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) +* `{ type: "date" }`: platform default date format +* `{ type: "time" }`: platform default time format +* `{ type: "datetime" }`: platform default datetime format +* `{ type: "custom", pattern: "..." }`: custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) The following example formats a date attribute using a custom month-year pattern: diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 951da56e30f..9d7954b4625 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -211,10 +211,10 @@ interface DateTimeFormatter extends SimpleFormatter { The `withConfig` method returns a **new formatter** with a different date pattern while preserving the user's locale. It accepts a `DateTimeFormatterConfig` with the following options: -* `{ type: "date" }` — platform default date format -* `{ type: "time" }` — platform default time format -* `{ type: "datetime" }` — platform default datetime format -* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) +* `{ type: "date" }`: platform default date format +* `{ type: "time" }`: platform default time format +* `{ type: "datetime" }`: platform default datetime format +* `{ type: "custom", pattern: "..." }`: custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) The following example formats a date attribute using a custom month-year pattern: diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md index 5ddcfe6afb3..c65d08e610d 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md @@ -183,10 +183,10 @@ interface DateTimeFormatter extends SimpleFormatter { The `withConfig` method returns a **new formatter** with a different date pattern while preserving the user's locale. It accepts a `DateTimeFormatterConfig` with the following options: -* `{ type: "date" }` — platform default date format -* `{ type: "time" }` — platform default time format -* `{ type: "datetime" }` — platform default datetime format -* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) +* `{ type: "date" }`: platform default date format +* `{ type: "time" }`: platform default time format +* `{ type: "datetime" }`: platform default datetime format +* `{ type: "custom", pattern: "..." }`: custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`) The following example formats a date attribute using a custom month-year pattern: From ae02303444a0b1a4be61108b35a6d7282673b087 Mon Sep 17 00:00:00 2001 From: ConnorLand Date: Wed, 18 Mar 2026 13:49:22 +0100 Subject: [PATCH 8/8] Clarify language --- .../pluggable-widgets/pluggable-widgets-client-apis/_index.md | 2 +- .../pluggable-widgets/pluggable-widgets-client-apis/_index.md | 2 +- .../pluggable-widgets/pluggable-widgets-client-apis-9/_index.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 46f3ca052b7..f9b3f58c6aa 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-10/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -178,7 +178,7 @@ interface SimpleFormatter { ##### Built-in Formatter Types {#built-in-formatter-types} -The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: +The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`: `NumberFormatter` and `DateTimeFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: ```ts type ValueFormatter = diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md index 9d7954b4625..c6ace502a26 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md @@ -176,7 +176,7 @@ interface SimpleFormatter { ##### Built-in Formatter Types {#built-in-formatter-types} -The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: +The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`: `NumberFormatter` and `DateTimeFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: ```ts type ValueFormatter = diff --git a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md index c65d08e610d..2c6b8ece941 100644 --- a/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md +++ b/content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md @@ -148,7 +148,7 @@ interface SimpleFormatter { ##### Built-in Formatter Types {#built-in-formatter-types} -The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: +The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter`: `NumberFormatter` and `DateTimeFormatter`. The actual type of `EditableValue.formatter` is `ValueFormatter` — a union that covers both built-in and plain formatters: ```ts type ValueFormatter =