|
| 1 | +## April 27 ([discuss](https://github.com/SimplrJS/simplr-forms/pull/29)) |
| 2 | + |
| 3 | +### Attendees |
| 4 | + |
| 5 | +* [Dovydas](https://twitter.com/dovydasnav) (QuatroDev) |
| 6 | +* [Martynas](https://twitter.com/MartinZilinskas) (QuatroDev) |
| 7 | + |
| 8 | +### What's new? |
| 9 | + |
| 10 | +`Modifiers` and `Normalizers` work properly with fields! |
| 11 | + |
| 12 | +### Soooo... What are those? |
| 13 | + |
| 14 | +Let's start with `Normalizers`. If you ever needed to make sure your input is all lower-case, upper-case or alphanumeric, think how would you approach that scenario. |
| 15 | + |
| 16 | +Now look at this. I introduce to you: `Normalizers`. |
| 17 | + |
| 18 | +Imagine you need a form for a promo code. It has a few limitations: it's upper-case and alphanumeric characters only. |
| 19 | + |
| 20 | +You could let user enter whatever input and then take what's needed, stripping all spaces and symbols away. |
| 21 | + |
| 22 | +But that is not user friendly, because user cannot see what's happening behind the scenes and their imput is being modifier without any visual feedback. |
| 23 | + |
| 24 | +You could also take `onChange` event and enforce required rules there, setting the value to the filtered one after each key stroke. |
| 25 | +But the logic gets messy and it's an imperative approach to solve this problem. |
| 26 | + |
| 27 | +What if you could take this familiar form application (yep, that's the whole application, if you didn't read [the last post](https://github.com/SimplrJS/simplr-forms/blob/master/docs/2017-04/2017-04-26.md)): |
| 28 | +```tsx |
| 29 | +import * as React from "react"; |
| 30 | +import * as ReactDOM from "react-dom"; |
| 31 | +import "tslib"; |
| 32 | +import { FormStore } from "simplr-forms-core/stores"; |
| 33 | +import { Form, Text, Submit } from "simplr-forms-dom"; |
| 34 | + |
| 35 | +export class Main extends React.Component<{}, { formId: string }> { |
| 36 | + protected onSubmit: any = (event: React.FormEvent<HTMLFormElement>, store: FormStore) => { |
| 37 | + console.log("Submitting..."); |
| 38 | + console.log(store.ToObject()); |
| 39 | + }; |
| 40 | + |
| 41 | + render() { |
| 42 | + return <Form onSubmit={this.onSubmit}> |
| 43 | + <label> |
| 44 | + Promo code: |
| 45 | + <Text name="PromoCode" /> |
| 46 | + </label> |
| 47 | + <Submit>Submit</Submit> |
| 48 | + </Form>; |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +ReactDOM.render(<Main />, document.getElementById("react-root")); |
| 53 | +``` |
| 54 | + |
| 55 | +And declare required rules well... In a declarative fashion? |
| 56 | + |
| 57 | +E.g. for upper-case, you import an `UpperCaseNormalizer` like this: |
| 58 | +```ts |
| 59 | +import { UpperCaseNormalizer } from "simplr-forms-core/normalizers"; |
| 60 | +``` |
| 61 | +And declare the rule right inside the field like this: |
| 62 | +```tsx |
| 63 | +<Form> |
| 64 | + <label> |
| 65 | + Promo code: |
| 66 | + <Text name="PromoCode"> |
| 67 | + <UpperCaseNormalizer /> |
| 68 | + </Text> |
| 69 | + </label> |
| 70 | + <Submit>Submit</Submit> |
| 71 | +</Form> |
| 72 | +``` |
| 73 | + |
| 74 | +Convenient, right? Now you think that the `UpperCaseNormalizer` is some complex peace of code, right? |
| 75 | + |
| 76 | +Well, decide for yourself, because the whole `UpperCaseNormalizer` looks like this: |
| 77 | +```ts |
| 78 | +import { BaseNormalizer } from "simplr-forms-core/normalizers"; |
| 79 | +import { FieldValue } from "simplr-forms-core/contracts"; |
| 80 | +import { ValueOfType } from "simplr-forms-core/utils"; |
| 81 | + |
| 82 | +export class UpperCaseNormalizer extends BaseNormalizer<{}, {}> { |
| 83 | + Normalize(value: FieldValue): FieldValue { |
| 84 | + if (ValueOfType<string>(value, UpperCaseNormalizer.name, "string")) { |
| 85 | + return value.toUpperCase(); |
| 86 | + } |
| 87 | + } |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +Library imports are organized and easily reachable. |
| 92 | + |
| 93 | +And what is `ValueOfType` thingy there? |
| 94 | + |
| 95 | +That's just a convenient helper function that checks if `typeof value === "string"` and throws an error with a proper message if it's not. Take it or leave it. The library is not opinionated about that. |
| 96 | + |
| 97 | +There's more. |
| 98 | + |
| 99 | +We only have our value normalized to upper-case now. What about alphanumeric part? |
| 100 | + |
| 101 | +Well, you can compose `Normalizers` and even decide the order of them as you wish, all still declaratively, like this: |
| 102 | +```tsx |
| 103 | +<Form> |
| 104 | + <label> |
| 105 | + Promo code: |
| 106 | + <Text name="PromoCode"> |
| 107 | + <UpperCaseNormalizer /> |
| 108 | + <AlphanumericNormalizer /> |
| 109 | + </Text> |
| 110 | + </label> |
| 111 | + <Submit>Submit</Submit> |
| 112 | +</Form> |
| 113 | +``` |
| 114 | + |
| 115 | +Now value will be upper-cased and all non-alphanumeric symbols filtered out. If you think that upper-casing should go after alphanumeric filter, you just change the order, still declaratively: |
| 116 | +```tsx |
| 117 | +<Form> |
| 118 | + <label> |
| 119 | + Promo code: |
| 120 | + <Text name="PromoCode"> |
| 121 | + <AlphanumericNormalizer /> |
| 122 | + <UpperCaseNormalizer /> |
| 123 | + </Text> |
| 124 | + </label> |
| 125 | + <Submit>Submit</Submit> |
| 126 | +</Form> |
| 127 | +``` |
| 128 | + |
| 129 | +Want something more? |
| 130 | + |
| 131 | +`Normalizers` are regular react components, therefore, they can take props. E.g.: |
| 132 | +```tsx |
| 133 | +<AlphanumericNormalizer allowSpaces={true} /> |
| 134 | +``` |
| 135 | +Now you can unleash the power of declarative rule listing and composition and use props for an easy control of `Normalizers` behaviour. |
| 136 | + |
| 137 | +When user is typing `discount123`, this is how it looks in the field (also, in the store): |
| 138 | + |
| 139 | + |
| 140 | + |
| 141 | +`Normalizers` enforced all declared rules. |
| 142 | + |
| 143 | +This is how you easily organize and reuse your normalization logic. |
| 144 | + |
| 145 | +### Amazing! What about `Modifiers`? |
| 146 | + |
| 147 | +`Modifiers` are another convenient feature. You use them just as you used `Normalizers`: declare inside the field. |
| 148 | + |
| 149 | +But what they do is a bit different: `Modifiers` format and parse value of the field. |
| 150 | + |
| 151 | +To be more specific: |
| 152 | +* When value comes from `FormStore` to the field, it is formatted. |
| 153 | +* When it changes, before going to `FormStore`, it is parsed. |
| 154 | + |
| 155 | +This enables you to have a `numeric` value in the store and a `string` one in the field. Or storing `Date` in the store and formatting it for user in a human-readable format. |
| 156 | + |
| 157 | +And `Normalizers` get an already parsed value, so you don't have to care about converting it to the right type in the `Normalizers` and it's the only thing you do in `Modifier`. [Separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) :+1: |
| 158 | + |
| 159 | +Example of `Modifier` usage: |
| 160 | +```tsx |
| 161 | +<Form onSubmit={this.onSubmit}> |
| 162 | + <label> |
| 163 | + Full name: |
| 164 | + <Text name="FullName"> |
| 165 | + <NumericModifier /> |
| 166 | + </Text> |
| 167 | + </label> |
| 168 | + <Submit>Submit</Submit> |
| 169 | +</Form> |
| 170 | +``` |
| 171 | + |
| 172 | +And you can also use both `Modifiers` and `Normalizers` in the same `Field`: |
| 173 | +```tsx |
| 174 | +<Form onSubmit={this.onSubmit}> |
| 175 | + <label> |
| 176 | + Full name: |
| 177 | + <Text name="FullName"> |
| 178 | + <NumericModifier /> |
| 179 | + <UpperCaseNormalizer /> |
| 180 | + </Text> |
| 181 | + </label> |
| 182 | + <Submit>Submit</Submit> |
| 183 | +</Form> |
| 184 | +``` |
| 185 | +Even if this case does not make much sense (numeric->upper-case), I'm sure someone will find a proper usage. |
| 186 | + |
| 187 | +### What's next? |
| 188 | + |
| 189 | +We’ll look at `Reset` and `Clear` buttons, how they work and what are they used for. We'll learn how `initialValue` and `defaultValue` can be used in a meaningful way. |
| 190 | + |
| 191 | +------------ |
| 192 | + |
| 193 | +The feedback and questions are more than welcome! |
| 194 | + |
| 195 | +------------ |
| 196 | + |
| 197 | +Please feel free to discuss these notes in the [corresponding pull request](https://github.com/SimplrJS/simplr-forms/pull/29). |
0 commit comments