[//]: # 'AUTO INSERT HEADER PREPUBLISH' # Formatting and Parsing ```js script import { html } from '@lion/core'; import '@lion/input/lion-input.js'; import { Unparseable } from '@lion/form-core'; import '../docs/helper-wc/h-output.js'; export default { title: 'Forms/System/Formatting and Parsing', }; ``` > For demo purposes, below we use `` which is a basic extension of ``. > Almost all fields share the same functionality as ``. ## Different values The `FormatMixin` which is used in all lion fields automatically keeps track of: - `modelValue`, which is a result of parsing - `formattedValue`, which is a result of formatting - `serializedValue`, which is a result of serializing Our fields can automatically format/parse/serialize user input or an input set imperatively by an Application Developer. Below are some concrete examples of implementations of formatters and parsers mimicking a (basic) amount input. > For an actual amount input, check out [lion-input-amount](?path=/docs/forms-lion-input-amount). > This comes with its own formatter, parser, serializer. ### Parsers & modelValue A parser should return a `modelValue`. The `modelValue` is the result of the parser function. It should be considered as the **internal value used for validation and reasoning/logic**. The `modelValue` is 'ready for consumption' by the outside world (think of a Date object or a float). The `modelValue` can (and is recommended to) be used as both input value and output value of the ``. In essence, the `modelValue` acts as a Single Source of Truth in our form fields and therefore a single way of programmatical interaction. Formatted values, serialized values and reflected-back view values are derived from it. You can listen to `model-value-changed` event on all fields. Internally this is also used as the main trigger for re-evaluating validation, visibility and interaction states. Examples: - For a `date input`: a String '20/01/1999' will be converted to new Date('1999/01/20') - For an `amount input`: a formatted String '1.234,56' will be converted to a Number: 1234.56 You can set a parser function on the `` to set parsing behavior. In this example, we parse the input and try to convert it to a `Number`. ```js preview-story export const parser = () => html` console.log(target)} > `; ``` #### Unparseable If a parser tries to parse and it returns undefined, the `modelValue` will be an instance of `Unparseable`. This object contains a type `'unparseable'`, and a `viewValue` which contains the String value of what the user tried to input. The formatted result of this that is reflected to the user will be the `viewValue` of the `Unparseable` instance, so basically nothing happens for the user. ```js preview-story export const unparseable = () => html` `; ``` ### Formatters A formatter should return a `formattedValue`. It accepts the current modelValue and an options object. Below is a very naive and limited parser that ignores non-digits. The formatter then uses `Intl.NumberFormat` to format it with thousand separators. Formatted value is reflected back to the user `on-blur` of the field, but only if the field has no errors (validation). ```js preview-story export const formatters = () => { const formatDate = (modelValue, options) => { if (!(typeof modelValue === 'number')) { return options.formattedValue; } return new Intl.NumberFormat('en-GB').format(modelValue); }; return html` `; }; ``` > The options object holds a fallback value that shows what should be presented on > screen when the user input resulted in an invalid `modelValue`. ### Serializers and deserializers A serializer converts the `modelValue` to a `serializedValue`. In this example, we decide we want to store the user input to our hypothetical database, but by parsing it with radix 8 first. A deserializer converts a value, for example one received from an API, to a `modelValue`. This can be useful for prefilling forms with data from APIs. > There is no `.deserializedValue` property that stays in sync by default. > You need to call `el.deserializer(el.modelValue)` manually yourself. ```js preview-story export const deSerializers = () => { const mySerializer = (modelValue, options) => { return parseInt(modelValue, 8); }; const myDeserializer = (myValue, options) => { return new Number(myValue); }; return html` `; }; ``` ## Flow Diagrams Below we show three flow diagrams to show the flow of formatting, serializing and parsing user input, with the example of a date input: ### Standard flow Where a user changes the input with their keyboard ```js preview-story export const standardFlow = () => html` `; ``` ### Unparseable flow Where a user sets the input to something that is not parseable by the parser ```js preview-story export const unparseableFlow = () => html` `; ``` ### Imperative / programmatic flow Where the developer sets the modelValue of the input programmatically ```js preview-story export const imperativeFlow = () => html` `; ```