Skip to content

Commit 6794092

Browse files
Backport the review changes to version 9 and 10
1 parent d4d48c0 commit 6794092

2 files changed

Lines changed: 200 additions & 60 deletions

File tree

  • content/en/docs/apidocs-mxsdk/apidocs
    • studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis
    • studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9

content/en/docs/apidocs-mxsdk/apidocs/studio-pro-11/pluggable-widgets/pluggable-widgets-client-apis/_index.md

Lines changed: 100 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -169,52 +169,53 @@ The `formatter` field on `EditableValue` is defined as follows:
169169
type ParseResult<T> = { valid: true; value: T } | { valid: false };
170170

171171
interface SimpleFormatter<T> {
172-
format(value: T | undefined): string;
173-
parse(value: string): ParseResult<T>;
174-
}
172+
format(value: T | undefined): string;
173+
parse(value: string): ParseResult<T>;
175174
}
176175
```
177176

178-
You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`):
177+
##### Built-in Formatter Types {#built-in-formatter-types}
179178

180-
```ts
181-
myDecimalAttribute.setFormatter({
182-
format(value: Big | undefined): string {
183-
return value !== undefined ? `$${Number(value).toFixed(2)}` : "";
184-
},
185-
parse(text: string): ParseResult<T> {
186-
const num = Number(text.replace(/[$,]/g, ""));
187-
return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) };
188-
}
189-
});
179+
The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter<T>`. The actual type of `EditableValue.formatter` is `ValueFormatter<T>` — a union that covers both built-in and plain formatters:
190180

181+
```ts
182+
type ValueFormatter<T> =
183+
| (TypedFormatter<T> & (NumberFormatter | DateTimeFormatter))
184+
| (SimpleFormatter<T> & { readonly type?: never });
191185
```
192186

193-
Call `setFormatter(undefined)` to reset the formatter to the platform default.
194-
195-
**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter<Date>`:
187+
Use the `type` property as a type guard to narrow to a specific built-in formatter before accessing its extra API:
196188

197189
```ts
198-
interface DateTimeFormatter {
199-
type: "datetime";
200-
format(value: Date | undefined): string;
201-
parse(value: string): { valid: true; value: Date } | { valid: false };
202-
withConfig(config: DateTimeFormatterConfig): DateTimeFormatter;
203-
getFormatPlaceholder(): string;
204-
config: DateTimeFormatterConfig;
190+
if (myAttribute.formatter.type === "datetime") {
191+
// DateTimeFormatter — has withConfig, getFormatPlaceholder
192+
} else if (myAttribute.formatter.type === "number") {
193+
// NumberFormatter — has withConfig
194+
} else {
195+
// Plain SimpleFormatter — string, enum, or boolean
205196
}
206197
```
207198

208-
You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly:
199+
##### DateTimeFormatter
200+
201+
**Date/DateTime** attributes receive a `DateTimeFormatter`, which extends `SimpleFormatter<Date>`:
209202

210203
```ts
211-
if (myAttribute.formatter.type === "datetime") {
212-
// Date-specific formatting logic
213-
} else {
214-
// String, number, enum, or boolean formatting logic
204+
interface DateTimeFormatter extends SimpleFormatter<Date> {
205+
readonly type: "datetime";
206+
readonly config: DateTimeFormatterConfig;
207+
withConfig(config: DateTimeFormatterConfig): DateTimeFormatter;
208+
getFormatPlaceholder(): string | undefined;
215209
}
216210
```
217211

212+
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:
213+
214+
* `{ type: "date" }` — platform default date format
215+
* `{ type: "time" }` — platform default time format
216+
* `{ type: "datetime" }` — platform default datetime format
217+
* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`)
218+
218219
The following example formats a date attribute using a custom month-year pattern:
219220

220221
```ts
@@ -227,13 +228,82 @@ if (myDateAttribute.formatter.type === "datetime") {
227228
}
228229
```
229230

230-
For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro:
231+
`getFormatPlaceholder` returns a locale-appropriate placeholder string for the active date pattern, useful for input field `placeholder` attributes:
232+
233+
```ts
234+
const placeholder = myDateAttribute.formatter.type === "datetime"
235+
? myDateAttribute.formatter.getFormatPlaceholder()
236+
: undefined;
237+
```
238+
239+
##### NumberFormatter
240+
241+
**Decimal**, **Integer**, and **Long** attributes receive a `NumberFormatter`, which extends `SimpleFormatter<Big>`:
242+
243+
```ts
244+
interface NumberFormatter extends SimpleFormatter<Big> {
245+
readonly type: "number";
246+
readonly config: NumberFormatterConfig;
247+
withConfig(config: NumberFormatterConfig): NumberFormatter;
248+
}
249+
```
250+
251+
`NumberFormatterConfig` has the following options:
252+
253+
```ts
254+
interface NumberFormatterConfig {
255+
readonly groupDigits: boolean; // e.g. 1,000,000
256+
readonly decimalPrecision?: number;
257+
}
258+
```
259+
260+
The following example disables the thousands separator and fixes the output to four decimal places:
261+
262+
```ts
263+
if (myNumberAttribute.formatter.type === "number") {
264+
const customFormatter = myNumberAttribute.formatter.withConfig({
265+
groupDigits: false,
266+
decimalPrecision: 4
267+
});
268+
const formatted = customFormatter.format(myNumberAttribute.value); // e.g. "1234.5600"
269+
}
270+
```
271+
272+
##### Plain SimpleFormatter
273+
274+
For **string**, **enumeration**, and **Boolean** attributes the platform provides a plain `SimpleFormatter<T>` 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`:
231275

232276
```ts
233277
// myEnumAttribute is an EditableValue<string>
234278
const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress"
235279
```
236280

281+
##### Custom Formatters via setFormatter
282+
283+
You can supply a fully custom formatter for any attribute type using `setFormatter`. The object must implement `format` and `parse`:
284+
285+
```ts
286+
myDecimalAttribute.setFormatter({
287+
format(value: Big | undefined): string {
288+
return value !== undefined ? `$${Number(value).toFixed(2)}` : "";
289+
},
290+
parse(text: string): { valid: true; value: Big } | { valid: false } {
291+
const num = Number(text.replace(/[$,]/g, ""));
292+
return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) };
293+
}
294+
});
295+
```
296+
297+
Call `setFormatter(undefined)` to reset the formatter to the platform default.
298+
299+
##### Quick Reference
300+
301+
| Formatter type | `type` value | `withConfig` | `getFormatPlaceholder` | Applies to |
302+
|---|---|---|---|---|
303+
| `DateTimeFormatter` | `"datetime"` |`DateTimeFormatterConfig` || `Date` |
304+
| `NumberFormatter` | `"number"` |`NumberFormatterConfig` || `Big` (Decimal, Integer, Long) |
305+
| `SimpleFormatter` | `undefined` ||| `string`, `boolean`, Enum |
306+
237307
### EditableFileValue {#editable-file-value}
238308

239309
`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:

content/en/docs/apidocs-mxsdk/apidocs/studio-pro-9/pluggable-widgets/pluggable-widgets-client-apis-9/_index.md

Lines changed: 100 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -141,52 +141,53 @@ The `formatter` field on `EditableValue` is defined as follows:
141141
type ParseResult<T> = { valid: true; value: T } | { valid: false };
142142

143143
interface SimpleFormatter<T> {
144-
format(value: T | undefined): string;
145-
parse(value: string): ParseResult<T>;
146-
}
144+
format(value: T | undefined): string;
145+
parse(value: string): ParseResult<T>;
147146
}
148147
```
149148

150-
You can supply a fully custom formatter using `setFormatter` (the object must implement `format` and `parse`):
149+
##### Built-in Formatter Types {#built-in-formatter-types}
151150

152-
```ts
153-
myDecimalAttribute.setFormatter({
154-
format(value: Big | undefined): string {
155-
return value !== undefined ? `$${Number(value).toFixed(2)}` : "";
156-
},
157-
parse(text: string): ParseResult<T> {
158-
const num = Number(text.replace(/[$,]/g, ""));
159-
return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) };
160-
}
161-
});
151+
The Mendix platform provides two typed, configurable built-in formatters that extend `SimpleFormatter<T>`. The actual type of `EditableValue.formatter` is `ValueFormatter<T>` — a union that covers both built-in and plain formatters:
162152

153+
```ts
154+
type ValueFormatter<T> =
155+
| (TypedFormatter<T> & (NumberFormatter | DateTimeFormatter))
156+
| (SimpleFormatter<T> & { readonly type?: never });
163157
```
164158

165-
Call `setFormatter(undefined)` to reset the formatter to the platform default.
166-
167-
**Date/DateTime** attributes have additional capabilities because of `DateTimeFormatter`, which extends `SimpleFormatter<Date>`:
159+
Use the `type` property as a type guard to narrow to a specific built-in formatter before accessing its extra API:
168160

169161
```ts
170-
interface DateTimeFormatter {
171-
type: "datetime";
172-
format(value: Date | undefined): string;
173-
parse(value: string): { valid: true; value: Date } | { valid: false };
174-
withConfig(config: DateTimeFormatterConfig): DateTimeFormatter;
175-
getFormatPlaceholder(): string;
176-
config: DateTimeFormatterConfig;
162+
if (myAttribute.formatter.type === "datetime") {
163+
// DateTimeFormatter — has withConfig, getFormatPlaceholder
164+
} else if (myAttribute.formatter.type === "number") {
165+
// NumberFormatter — has withConfig
166+
} else {
167+
// Plain SimpleFormatter — string, enum, or boolean
177168
}
178169
```
179170

180-
You can check `formatter.type` to detect the attribute's data type at runtime and branch your widget logic accordingly:
171+
##### DateTimeFormatter
172+
173+
**Date/DateTime** attributes receive a `DateTimeFormatter`, which extends `SimpleFormatter<Date>`:
181174

182175
```ts
183-
if (myAttribute.formatter.type === "datetime") {
184-
// Date-specific formatting logic
185-
} else {
186-
// String, number, enum, or boolean formatting logic
176+
interface DateTimeFormatter extends SimpleFormatter<Date> {
177+
readonly type: "datetime";
178+
readonly config: DateTimeFormatterConfig;
179+
withConfig(config: DateTimeFormatterConfig): DateTimeFormatter;
180+
getFormatPlaceholder(): string | undefined;
187181
}
188182
```
189183

184+
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:
185+
186+
* `{ type: "date" }` — platform default date format
187+
* `{ type: "time" }` — platform default time format
188+
* `{ type: "datetime" }` — platform default datetime format
189+
* `{ type: "custom", pattern: "..." }` — custom Unicode date pattern (for example `"EEEE"`, `"dd MMMM"`, `"MMMM YYYY"`)
190+
190191
The following example formats a date attribute using a custom month-year pattern:
191192

192193
```ts
@@ -199,13 +200,82 @@ if (myDateAttribute.formatter.type === "datetime") {
199200
}
200201
```
201202

202-
For enumeration and Boolean attributes, `format` converts the raw value into a human-readable caption as configured in Studio Pro:
203+
`getFormatPlaceholder` returns a locale-appropriate placeholder string for the active date pattern, useful for input field `placeholder` attributes:
204+
205+
```ts
206+
const placeholder = myDateAttribute.formatter.type === "datetime"
207+
? myDateAttribute.formatter.getFormatPlaceholder()
208+
: undefined;
209+
```
210+
211+
##### NumberFormatter
212+
213+
**Decimal**, **Integer**, and **Long** attributes receive a `NumberFormatter`, which extends `SimpleFormatter<Big>`:
214+
215+
```ts
216+
interface NumberFormatter extends SimpleFormatter<Big> {
217+
readonly type: "number";
218+
readonly config: NumberFormatterConfig;
219+
withConfig(config: NumberFormatterConfig): NumberFormatter;
220+
}
221+
```
222+
223+
`NumberFormatterConfig` has the following options:
224+
225+
```ts
226+
interface NumberFormatterConfig {
227+
readonly groupDigits: boolean; // e.g. 1,000,000
228+
readonly decimalPrecision?: number;
229+
}
230+
```
231+
232+
The following example disables the thousands separator and fixes the output to four decimal places:
233+
234+
```ts
235+
if (myNumberAttribute.formatter.type === "number") {
236+
const customFormatter = myNumberAttribute.formatter.withConfig({
237+
groupDigits: false,
238+
decimalPrecision: 4
239+
});
240+
const formatted = customFormatter.format(myNumberAttribute.value); // e.g. "1234.5600"
241+
}
242+
```
243+
244+
##### Plain SimpleFormatter
245+
246+
For **string**, **enumeration**, and **Boolean** attributes the platform provides a plain `SimpleFormatter<T>` 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`:
203247

204248
```ts
205249
// myEnumAttribute is an EditableValue<string>
206250
const caption = myEnumAttribute.formatter.format(myEnumAttribute.value); // e.g. "In Progress"
207251
```
208252

253+
##### Custom Formatters via setFormatter
254+
255+
You can supply a fully custom formatter for any attribute type using `setFormatter`. The object must implement `format` and `parse`:
256+
257+
```ts
258+
myDecimalAttribute.setFormatter({
259+
format(value: Big | undefined): string {
260+
return value !== undefined ? `$${Number(value).toFixed(2)}` : "";
261+
},
262+
parse(text: string): { valid: true; value: Big } | { valid: false } {
263+
const num = Number(text.replace(/[$,]/g, ""));
264+
return isNaN(num) ? { valid: false } : { valid: true, value: new Big(num) };
265+
}
266+
});
267+
```
268+
269+
Call `setFormatter(undefined)` to reset the formatter to the platform default.
270+
271+
##### Quick Reference
272+
273+
| Formatter type | `type` value | `withConfig` | `getFormatPlaceholder` | Applies to |
274+
|---|---|---|---|---|
275+
| `DateTimeFormatter` | `"datetime"` |`DateTimeFormatterConfig` || `Date` |
276+
| `NumberFormatter` | `"number"` |`NumberFormatterConfig` || `Big` (Decimal, Integer, Long) |
277+
| `SimpleFormatter` | `undefined` ||| `string`, `boolean`, Enum |
278+
209279
### ModifiableValue {#modifiable-value}
210280

211281
`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:

0 commit comments

Comments
 (0)