Input Masking with Vue @shortdiv
A presentation at VueConf US in March 2019 in Tampa, FL, USA by Divya
Input Masking with Vue @shortdiv
Divya Sasidharan Developer Advocate
0.00
0.01
0.12
1.23
12.34
123.45
1,234.56
123.45
12.34
1.23
0.12
0.01
0.00
$0
$ 1
$ 12
$ 123
$ 1,234
$ 1,234 5
$ 1,234 56
$ 1,234 5
$ 1,234
$ 123
$ 12
$ 1
$0
Why use this pattern? I don’t have any UX research to cite, but anecdotally, I like it when inputs that expect data in a specific format use an input mask. — Chris Coyier
Input Events The Role of Reactivity Reusable component patterns
0.00
Requirements Allow only numbers Add format for dollars and cents
Input Events
Patterns Capturing Key Events 0.00
Patterns Capturing Key Events
Patterns Capturing Key Events 1
Patterns Capturing Key Events 1 oninput
Patterns Capturing Key Events 1 @input
<input type=”text” id=“currency” placeholder=”0.00” @input=”formatCashMoney” :value=”formattedCashMoney” />
<input type=”text” id=“currency” placeholder=”0.00” @input=”formatCashMoney” :value=”formattedCashMoney” :value=“formattedCashMoney” />
<input type=”text” id=“currency” placeholder=”0.00” /> v-model=”formattedCashMoney”
<template> <input type=”text” id=”currency” v-model=”formattedCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } } } </script>
<template> <input type=”text” id=”currency” v-model=”formattedCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, } </script>
<template> <input type=”text” id=”currency” v-model=”formattedCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } } } </script>
<template> <input type=”text” id=”currency” v-model=”formattedCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() { //format cashMoney } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=“formatCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() { //format cashMoney } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=“formatCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() { //format cashMoney } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=“formatCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { cashMoney: null formattedCashMoney: null } }, methods: { formatCashMoney() { //format cashMoney } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() { //format cashMoney } } } </script>
Requirements Allow only numbers Add format for dollars and cents
<template> <input type=”text” id=”currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() { //format cashMoney } } } </script>
<template> <input type=”text” id=”currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() { //format cashMoney } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { var key = e.key } } } </script>
<template> <input type=”text” id=”currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() {{ formatCashMoney(e) var key = e.key if (!/^\d+/g.test(key)) { e.preventDefault() } } } } </script>
Working Demo
keydown > keypress > input > keyup
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { var key = e.key if (!/^\d+/g.test(key)) { e.preventDefault() } } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @input=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { var key = e.key if (!/^\d+/g.test(key)) { e.preventDefault() } } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { var key = e.key if (!/^\d+/g.test(key)) { e.preventDefault() } } } } </script>
Working Demo
Requirements Allow only numbers Add format for dollars and cents
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=”formatCashMoney” /> </template> <script> export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { var key = e.key if (!/^\d+/g.test(key)) { e.preventDefault() } } } } </script>
<template> <input type=”text” id=”currency” :value=”formattedCashMoney” @keydown=”formatCashMoney” /> </template> <script> import { wearMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { … } } this.formattedCashMoney = wearMask(e.target.value) } </script>
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) } function decimalize(numstr) { if (numstr.length > 1) { let dp = numstr.substring(numstr.length-2, numstr.length) let denom = numstr.substring(0, numstr.length - 2) if (denom.substring(0,1) === “0”) { denom = denom.substring(1, denom.length) } return ${denom}.${dp}
} else { return 0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); }
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) }
function decimalize(numstr) decimalize(numstr) {{ if (numstr.length >> 1) 1) {{ let dp = numstr.substring(numstr.length-2, numstr.substring(numstr.length-2, numstr.length) numstr.length) let denom = numstr.substring(0, numstr.substring(0, numstr.length numstr.length — 2) 2) if (denom.substring(0,1) (denom.substring(0,1) === === “0”) “0”) {{ denom = denom.substring(1, denom.substring(1, denom.length) denom.length) } return ${denom}.${dp}
${denom}.${dp}
} else { return 0.0${numstr}
0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); }
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) }
function decimalize(numstr) decimalize(numstr) {{ if (numstr.length >> 1) 1) {{ let dp = numstr.substring(numstr.length-2, numstr.substring(numstr.length-2, numstr.length) numstr.length) let denom = numstr.substring(0, numstr.substring(0, numstr.length numstr.length — 2) 2) if (denom.substring(0,1) (denom.substring(0,1) === === “0”) “0”) {{ denom = denom.substring(1, denom.substring(1, denom.length) denom.length) } return ${denom}.${dp}
${denom}.${dp}
} else { return 0.0${numstr}
0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); }
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) }
function decimalize(numstr) decimalize(numstr) {{ if (numstr.length >> 1) 1) {{ let dp = numstr.substring(numstr.length-2, numstr.substring(numstr.length-2, numstr.length) numstr.length) let denom = numstr.substring(0, numstr.substring(0, numstr.length numstr.length — 2) 2) if (denom.substring(0,1) (denom.substring(0,1) === === “0”) “0”) {{ denom = denom.substring(1, denom.substring(1, denom.length) denom.length) } return ${denom}.${dp}
${denom}.${dp}
} else { return 0.0${numstr}
0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); }
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) }
function decimalize(numstr) decimalize(numstr) {{ if (numstr.length >> 1) 1) {{ let dp = numstr.substring(numstr.length-2, numstr.substring(numstr.length-2, numstr.length) numstr.length) let denom = numstr.substring(0, numstr.substring(0, numstr.length numstr.length — 2) 2) if (denom.substring(0,1) (denom.substring(0,1) === === “0”) “0”) {{ denom = denom.substring(1, denom.substring(1, denom.length) denom.length) } return ${denom}.${dp}
${denom}.${dp}
} else { return 0.0${numstr}
0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); }
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) } function decimalize(numstr) { if (numstr.length > 1) { let dp = numstr.substring(numstr.length-2, numstr.length) let denom = numstr.substring(0, numstr.length - 2) if (denom.substring(0,1) === “0”) { denom = denom.substring(1, denom.length) } return ${denom}.${dp}
} else { return 0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); }
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) } function decimalize(numstr) { if (numstr.length > 1) { let dp = numstr.substring(numstr.length-2, numstr.length) let denom = numstr.substring(0, numstr.length - 2) if (denom.substring(0,1) === “0”) { denom = denom.substring(1, denom.length) } return ${denom}.${dp}
} else { return 0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); }
thousandths 123456 cents
thousandths 1,234.56 cents
Working Demo
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=”formatCashMoney” /> </template> <script> import { wearMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney() { … } } this.formattedCashMoney = wearMask(e.target.value) } </script>
keydown > keypress > input > keyup
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=”formatCashMoney” /> </template> <script> import { wearMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { … } } this.formattedCashMoney = wearMask(e.target.value) } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=“formatCashMoney” @keydown=”formatCashMoney” /> </template> <script> import { wearMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { formatCashMoney(e) { … } } this.formattedCashMoney = wearMask(e.target.value) } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=“validateInput” @keydown=”validateInput” @input=“formatInput” @input=”formatInput” /> </template> <script> import { wearMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { validateInput(e) { … } formatInput(e) { this.formattedCashMoney = wearMask(e.target.value) } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=“validateInput” @keydown=”validateInput” @input=“formatInput” @input=”formatInput” /> </template> <script> import { wearMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { validateInput(e) { … } formatInput(e) { this.formattedCashMoney = wearMask(e.target.value) } } }c } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=”validateInput” @input=”formatInput” /> </template> <script> import { wearMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { validateInput(e) { … } formatInput(e) { this.formattedCashMoney = wearMask(e.target.value) } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=“validateInput” @keydown=”validateInput” @input=“formatInput” @input=”formatInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { validateInput(e) { … } formatInput(e) { let unformatted = removeMask(e.target.value) this.formattedCashMoney = wearMask(e.target.value) } } } </script>
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) } function decimalize(numstr) { if (numstr.length > 1) { let dp = numstr.substring(numstr.length-2, numstr.length) let denom = numstr.substring(0, numstr.length - 2) if (denom.substring(0,1) === “0”) { denom = denom.substring(1, denom.length) } return ${denom}.${dp}
} else { return 0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); } function removeMask(str) { return numstr.replace(/\D+/g, “”); }
function wearMask (str) { let num = decimalize(str) num = separateByThousandths(num, “,”) } function decimalize(numstr) { if (numstr.length > 1) { let dp = numstr.substring(numstr.length-2, numstr.length) let denom = numstr.substring(0, numstr.length - 2) if (denom.substring(0,1) === “0”) { denom = denom.substring(1, denom.length) } return ${denom}.${dp}
} else { return 0.0${numstr}
} } function separateByThousandths(str, delimiter) { return str.replace(/\B(?=(\d{3})+(?!\d))/g, ${delimiter}
); } function removeMask(str) { return numstr.replace(/\D+/g, “”); }
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=”validateInput” @input=”formatInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { validateInput(e) { … } formatInput(e) { let unformatted = removeMask(e.target.value) this.formattedCashMoney = wearMask(e.target.value) } } } </script>
Requirements Allow only numbers Allowformat for delete/backspace Add for dollars and cents
The Role of Reactivity
0.00
Reactivity Methods methods: { onInput() {}, onKeyPress() {}, onKeyDown() {} … }
<input type=”text” id=”currency” :value=”formattedCashMoney” @input=”formatInput” @keydown=”validateInput” />
<input type=”text” id=”currency” :value=”formattedCashMoney” @input=”formatInput” @keydown=”validateInput” />
Reactivity Computed Property computed: { currentMask() { // format // } }
<input type=”text” id=”currency” :value=”formattedCashMoney” @input=”formatInput” @keydown=”validateInput” />
<template> <input type=”text” id=”currency” :value=”formattedCashMoney” @keydown=”validateInput” @input=”formatInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { formattedCashMoney: null } }, methods: { validateInput(e) { … } formatInput(e) { let unformattedVal = removeMask(e.target.value) this.formattedCashMoney = wearMask(unformattedVal) } } } </script>
<template> <input type=”text” id=”currency” :value=”formattedCashMoney” @keydown=”validateInput” @input=”updateInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { unformatted: null } }, methods: { validateInput(e) { … } updateInput(e) { this.unformatted = removeMask(e.target.value) } }, computed: { formattedCashMoney() { return wearMask(this.unformatted) } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=”validateInput” @input=”formatInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { unformatted: null } }, methods: { validateInput(e) { … } updateInput(e) { this.unformatted = removeMask(e.target.value) } }, computed: { formattedCashMoney() { return wearMask(this.unformatted) } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=“validateInput” @input=“formatInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { unformatted: null } }, methods: { validateInput(e) { … } updateInput(e) { this.unformatted = removeMask(e.target.value) } }, computed: { formattedCashMoney() { return wearMask(this.unformatted) } } } </script>
<template> <input type=”text” id=“currency” :value=”formattedCashMoney” @keydown=“validateInput” @input=“updateInput” @input=”updateInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { unformatted: null } }, methods: { validateInput(e) { … } updateInput(e) { this.unformatted = removeMask(e.target.value) } }, computed: { formattedCashMoney: {{ formattedCashMoney() return wearMask(this.unformatted) } } } </script>
Working Demo
Reactivity Computed Property computed: { currentMask() { get(){ … } set(){ … } } }
<template> <input type=”text” id=”currency” :value=”formattedCashMoney” @input=”updateInput” @keydown=”validateInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { unformatted: null } }, methods: { validateInput(e) { … } updateInput(e) { this.unformatted = removeMask(e.target.value) } }, computed: { formattedCashMoney() { return wearMask(this.unformatted) } } } </script>
<template> <input type=”text” id=”currency” v-model=”formattedCashMoney” @keydown=”validateInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { formatted: null } }, methods: { validateInput(e) { … } }, computed: { formattedCashMoney() { get() { … }, set() { … } } } } </script>
<template> <input type=”text” id=”currency” v-model=”formattedCashMoney” @keydown=”validateInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { formatted: null } }, methods: { validateInput(e) { … } }, computed: { formattedCashMoney() { get() { return this.formatted }, set() { … } } } } </script>
<template> <input type=”text” id=”currency” v-model=”formattedCashMoney” @keydown=”validateInput” /> </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, data () { return { formatted: null } }, methods: { validateInput(e) { … } }, computed: { formattedCashMoney() { get() { return this.formatted }, set(newVal) { let val = removeMask(newVal) this.formatted = wearMask(this.unformatted) } } } } </script>
Working Demo
Reusable Components
0.00
(###)-###-####
MM/DD/YYYY
Component Pattern Renderless Components export default { render(h) { return this.$scopedSlots.default({ … }) } }
<v-mask> //some children nodes// </v-mask>
<v-mask v-slot:default=”{ … }” > //some children nodes// </v-mask>
<v-mask v-slot:default=”{ formattedValue, input, keydown }” > <label> <input type=”text” :value=”formattedValue” @input=”input” @keydown=”keydown” /> <label> </v-mask>
<v-mask v-slot:default=“{ v-slot:default=”{ formattedValue, input, keydown }” }” > <label> <input type=”text” :value=“formattedValue” :value=”formattedValue” @input=“input” @input=”input” @keydown=”keydown” @keydown=“keydown” /> <label> </v-mask>
<v-mask v-slot:default=”{ formattedValue, input, keydown }” > <label> <input type=”text” :value=”formattedValue” @input=”input” @keydown=”keydown” /> <label> </v-mask>
<v-mask v-slot:default=“{ v-slot:default=”{ formattedValue, listeners }” }” > <label> <input type=”text” :value=”formattedValue” v-on=”listeners” /> <label> </v-mask>
<v-mask v-slot:default=”{ formattedValue, listeners }” > <label> <input type=”text” :value=”formattedValue” v-on=”listeners” /> <label> </v-mask>
export default { name: “v-mask”, data() { return { formatted: “0.00” }; }, render() { return this.$scopedSlots.default({ formattedValue: this.formatted, listeners: { keydown: e => { … }, input: e => { … } } }) } }
export default { name: “v-mask”, data() { return { formatted: “0.00” }; }, render() { return this.$scopedSlots.default({ formattedValue: this.formatted, listeners: { keydown: e => { … }, input: e => { … } } }) } }
export default { name: “v-mask”, “v-mask”, data() { return { formatted: “0.00” “0.00” }; }, render() { return this.$scopedSlots.default({ formattedValue: this.formatted, listeners: { keydown: e => { … }, input: e => { … } } }) } }
export default { name: “v-mask”, “v-mask”, data() { return { formatted: “0.00” }; }, render() { return this.$scopedSlots.default({ formattedValue: this.formatted, listeners: { keydown: e => { … }, input: e => { … } } }) } }
Component Pattern Directives directives: { mask: { bind(){ … } inserted(){ … } update(){ … } componentUpdated(){ … } unbind(){ … } } }
<template> <input type=”text” id=”currency” v-mask=”’(###)###-####’” > </template> <script> export default { name: “v-dinero”, directives: { mask: { bind() {…} componentUpdated() {…} } }, } </script>
<template> <input type=”text” id=”currency” v-mask=”’(###)###-####’” > </template> <script> export default { name: “v-dinero”, directives: { mask: { bind() {…} componentUpdated() {…} } }, } </script>
<template> <input type=”text” id=”currency” v-mask=”’(###)###-####’” > </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, directives: { mask: { bind(el, { value }) { const mask = value el.value = wearMask(el.target.value, mask); }, componentUpdated() {…} } }, } </script>
<template> <input type=”text” id=”currency” v-mask=”’(###)###-####’” > </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero”, directives: { mask: { bind(el, { value }) { const mask = value el.value = wearMask(el.target.value, mask); }, componentUpdated componentUpdated(el, { value }) { const mask = value let unformatted = removeMask(el.target.value) el.value = wearMask(unformatted, mask); } } }, } </script>
<template> <input type=”text” id=”currency” v-mask=”’(###)###-####’” v-model=”currentMask” > </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero data() { return { currentMask: null } }, directives: { mask: { bind(el, { value }) { const mask = value el.value = wearMask(el.target.value, mask); }, componentUpdated(el, { value }) { const mask = value let unformatted = removeMask(el.target.value) el.value = wearMask(unformatted, mask); } } }, } </script>
<template> <input type=”text” id=”currency” v-mask=”’(###)###-####’” v-model=”currentMask” > </template> <script> import { wearMask, removeMask } from “./utils” export default { name: “v-dinero data() { return { currentMask: null } }, directives: { mask: { bind(el, { value }) { const mask = value el.value = wearMask(el.target.value, mask); }, componentUpdated(el, { value }) { const mask = value let unformatted = removeMask(el.target.value) el.value = wearMask(unformatted, mask); } } }, } </script>
Component Pattern Hooks ?????????????????????
Component Pattern “Hooks” ?????????????????????
Component Pattern “Hooks” Compositional Functions ?????????????????????
Mixins can’t consume and use state from one to another, but Hooks can. This means that if we need to chain encapsulated logic, it’s now possible with Hooks. — Evan You Why use this pattern?
<input type=”text” v-model=”formatted” @keydown=”validateInput” >
<input type=”text” :value=”formatted.get()” @input=“formatted.set(e)” @keydown=“validateInput” >
import { useData, useComputed } from “vue-hooks”; export function computeMask() { function wearMask(numstr) { //format code// } const data = useData({ unformatted: null }); } const computed = useComputed(() => { return { formatted: { get() { return data.unformatted; }, set(e) { data.unformatted = wearMask(e.target.value); } } } } return { computed };
import { useData, useComputed } from “vue-hooks”; export function computeMask() { function wearMask(numstr) { //format code// } const data = useData({ unformatted: null }); } const computed = useComputed(() => { return { formatted: { get (){{ get() return data.unformatted; }, set(e) { data.unformatted = wearMask(e.target.value); } } } } return { computed };
import { useData, useComputed } from “vue-hooks”; export function computeMask() { function wearMask(numstr) { //format code// } const data = useData({ unformatted: null }); } const computed = useComputed(() => { return { formatted: { get (){{ get() return data.unformatted; }, set(e) { data.unformatted = wearMask(e.target.value); } } } } return { computed };
import { useData, useComputed } from “vue-hooks”; export function computeMask() { function wearMask(numstr) { //format code// } const data = useData({ unformatted: null }); } const computed = useComputed(() => { return { formatted: { get() { return data.unformatted; }, set(e) { data.unformatted = wearMask(e.target.value); } } } } return { computed };
import { useData, useComputed } from “vue-hooks”; export function computeMask() { function wearMask(numstr) { //format code// } const data = useData({ unformatted: null }); } const computed = useComputed(() => { return { formatted: { get() { return data.unformatted; }, set(e) { data.unformatted = wearMask(e.target.value); } } } } return { computed };
<template> <input type=”text” :value=”formatted.get()” @input=”formatted.set(e)” /> </template> <script> import { computeMask } from “../hooks/computeMask” export default { name: “VDinero”, hooks() { const { computed } = computeMask(); const { formatted } = computed } return { formatted }; } </script>
<template> <input type=“text” :value=”formatted.get()” :value=“formatted.get()” @input=”formatted.set(e)” > /> </template> <script> import { computeMask } from “../hooks/computeMask” “../hooks/computeMask” export default { name: “VDinero”, hooks() { const { computed } = computeMask(); const { formatted } = computed } return { formatted }; } </script>
<template> <input type=“text” :value=”formatted.get()” :value=“formatted.get()” @input=”formatted.set(e)” /> </template> <script> import { computeMask } from “../hooks/computeMask” export default { name: “VDinero”, hooks() { const { computed } = computeMask(); const { formatted } = computed } return { formatted }; } </script>
<template> <input type=”text” :value=”formatted.get()” @input=”formatted.set(e)” /> </template> <script> import { computeMask } from “../hooks/computeMask” export default { name: “VDinero”, hooks() { const { computed } = computeMask(); const { formatted } = computed } return { formatted }; } </script>
Why use this pattern? Maybe don’t use that… — Vue people I chatted with
import { value, computed } from ‘@vue/observer’ export function useComputeMask() { const unformatted = value(0) const formatted = computed( () => unformatted.value, val => { let unformattedVal = removeMask(val) unformatted.value = wearMask(unformattedVal) } ) return { formatted } }
import { value, computed } from ‘@vue/observer’ ‘@vue/observer’ export function useComputeMask() { const unformatted = value(0) const formatted = computed( () => unformatted.value, val => { let unformattedVal = removeMask(val) unformatted.value = wearMask(unformattedVal) } ) return { formatted } }
import { value, computed } from ‘@vue/observer’ ‘@vue/observer’ export function useComputeMask() { const unformatted = value(0) const formatted = computed( () => unformatted.value, val => { let unformattedVal = removeMask(val) unformatted.value = wearMask(unformattedVal) } ) return { formatted } }
import { value, computed } from ‘@vue/observer’ ‘@vue/observer’ export function useComputeMask() { const unformatted = value(0) const formatted = computed( () => unformatted.value, val => { let unformattedVal = removeMask(val) unformatted.value = wearMask(unformattedVal) } ) return { formatted } }
import { value, computed } from ‘@vue/observer’ ‘@vue/observer’ export function useComputeMask() { const unformatted = value(0) const formatted = computed( () => unformatted.value, val => { let unformattedVal = removeMask(val) unformatted.value = wearMask(unformattedVal) } ) } return { formatted }
import { value, computed } from ‘@vue/observer’ ‘@vue/observer’ export function useComputeMask() { const unformatted = value(0) const formatted = computed( () => unformatted.value, val => { let unformattedVal = removeMask(val) unformatted.value = wearMask(unformattedVal) } ) } return { formatted }
import { value, computed } from ‘@vue/observer’ export function useComputeMask() { const unformatted = value(0) const formatted = computed( () => unformatted.value, val => { let unformattedVal = removeMask(val) unformatted.value = wearMask(unformattedVal) } ) return { formatted } }
<template> <input type=”text” v-model=”formatted” /> </template> <script> import { useComputemask } from “../cp” export default { name: “VDinero”, data() { const { formatted } = useComputemask(); } return { formatted }; } </script>
Input Events The Role of Reactivity Reusable component patterns
Methods, Computeds, Directives, Renderless Components, Hooks Compositional Functions, Oh my!
🤔
Usability User Experience Developer Ergonomics
Thanks! @shortdiv