diff --git a/js/components/clin_dollar_amount.js b/js/components/clin_dollar_amount.js index 5179a82a..ccebed68 100644 --- a/js/components/clin_dollar_amount.js +++ b/js/components/clin_dollar_amount.js @@ -1,161 +1,33 @@ -import MaskedInput, { conformToMask } from 'vue-text-mask' import inputValidations from '../lib/input_validations' -import { formatDollars } from '../lib/dollars' -import { emitEvent } from '../lib/emitters' +import TextInputMixin from '../mixins/text_input_mixin' export default { name: 'clindollaramount', - components: { - MaskedInput, - }, + mixins: [TextInputMixin], props: { - name: String, - validation: { - type: String, - default: () => 'clinDollars', - }, - initialValue: { - type: String, - default: () => '', - }, - initialErrors: { - type: Array, - default: () => [], - }, - - optional: Boolean, fundingValid: Boolean, - watch: { - type: Boolean, - default: false, - }, - }, - - data: function() { - return { - showErrorState: - (this.initialErrors && this.initialErrors.length) || false, - showValidationState: false, - mask: inputValidations[this.validation].mask, - pipe: inputValidations[this.validation].pipe || undefined, - keepCharPositions: - inputValidations[this.validation].keepCharPositions || false, - validationError: - this.initialErrors.join(' ') || - inputValidations[this.validation].validationError, - value: this.initialValue, - modified: false, - } }, computed: { rawValue: function() { return this._rawValue(this.value) }, - showError: function() { - return this.showErrorState || !this.fundingValid + showFundingError: function() { + return this.showError || !this.fundingValid }, - showValid: function() { - return this.showValidationState && this.fundingValid + showFundingValid: function() { + return this.showValid && this.fundingValid }, }, - - mounted: function() { - if (this.value) { - this._checkIfValid({ - value: this.value, - invalidate: true, - showValidationStateationIcon: false, - }) - - if (this.mask && this.validation !== 'email') { - const mask = - typeof this.mask.mask !== 'function' - ? this.mask - : mask.mask(this.value).filter(val => val !== '[]') - - this.value = conformToMask(this.value, mask).conformedValue - } - } - }, - - created: function() { - emitEvent('field-mount', this, { - optional: this.optional, - name: this.name, - valid: this._isValid(this.value), - }) + watch: { + fundingValid: function(oldVal, newVal) { + this._checkIfValid({ value: this.value, invalidate: true }) + }, }, methods: { - // When user types a character - onInput: function(e) { - // When we use the native textarea element, we receive an event object - // When we use the masked-input component, we receive the value directly - const value = typeof e === 'object' ? e.target.value : e - this.value = value - this.modified = true - this._checkIfValid({ value }) - }, - - // When field is blurred (un-focused) - onChange: function(e) { - // Only invalidate the field when it blurs - this._checkIfValid({ value: e.target.value, invalidate: true }) - }, - - onBlur: function(e) { - if (!(this.optional && e.target.value === '')) { - this._checkIfValid({ value: e.target.value.trim(), invalidate: true }) - } else if (this.modified && !this.optional) { - this._checkIfValid({ value: e.target.value.trim(), invalidate: true }) - } - this.value = e.target.value.trim() - let value = Number.isNaN(e.target.value) ? '0' : e.target.value - this.value = formatDollars(this._rawValue(value)) - }, - - _checkIfValid: function({ - value, - invalidate = false, - showValidationStateationIcon = true, - }) { - const valid = this._isValid(value) - if (this.modified) { - this.validationError = inputValidations[this.validation].validationError - } - - // Show error messages or not - if (valid) { - this.showErrorState = false - } else if (invalidate) { - this.showErrorState = true - } - - if (showValidationStateationIcon) { - this.showValidationState = this.value != '' && valid - } - - // Emit a change event - emitEvent('field-change', this, { - value: this._rawValue(value), - valid: this._isValid(value), - name: this.name, - watch: this.watch, - }) - }, - - _rawValue: function(value) { - return inputValidations[this.validation].unmask.reduce( - (currentValue, character) => { - return currentValue.split(character).join('') - }, - value - ) - }, - _validate: function(value) { const rawValue = this._rawValue(value) if (rawValue < 0 || rawValue > 1000000000 || !this.fundingValid) { @@ -163,18 +35,5 @@ export default { } return inputValidations[this.validation].match.test(rawValue) }, - - _isValid: function(value) { - let valid = this._validate(value) - if (!this.modified && this.initialErrors && this.initialErrors.length) { - valid = false - } else if (this.optional && value === '') { - valid = true - } else if (!this.optional && value === '') { - valid = false - } - - return valid - }, }, } diff --git a/js/components/text_input.js b/js/components/text_input.js index 1e728ee7..9f91c832 100644 --- a/js/components/text_input.js +++ b/js/components/text_input.js @@ -1,173 +1,6 @@ -import MaskedInput, { conformToMask } from 'vue-text-mask' -import inputValidations from '../lib/input_validations' -import { formatDollars } from '../lib/dollars' -import { emitEvent } from '../lib/emitters' +import TextInputMixin from '../mixins/text_input_mixin' export default { name: 'textinput', - - components: { - MaskedInput, - }, - - props: { - name: String, - validation: { - type: String, - default: () => 'anything', - }, - initialValue: { - type: String, - default: () => '', - }, - initialErrors: { - type: Array, - default: () => [], - }, - paragraph: String, - noMaxWidth: String, - optional: Boolean, - watch: { - type: Boolean, - default: false, - }, - }, - - data: function() { - return { - showError: (this.initialErrors && this.initialErrors.length) || false, - showValid: false, - mask: inputValidations[this.validation].mask, - pipe: inputValidations[this.validation].pipe || undefined, - keepCharPositions: - inputValidations[this.validation].keepCharPositions || false, - validationError: - this.initialErrors.join(' ') || - inputValidations[this.validation].validationError, - value: this.initialValue, - modified: false, - } - }, - - computed: { - rawValue: function() { - return this._rawValue(this.value) - }, - }, - - mounted: function() { - if (this.value) { - this._checkIfValid({ - value: this.value, - invalidate: true, - showValidationIcon: false, - }) - - if (this.mask && this.validation !== 'email') { - const mask = - typeof this.mask.mask !== 'function' - ? this.mask - : mask.mask(this.value).filter(val => val !== '[]') - - this.value = conformToMask(this.value, mask).conformedValue - } - } - }, - - created: function() { - emitEvent('field-mount', this, { - optional: this.optional, - name: this.name, - valid: this._isValid(this.value), - }) - }, - - methods: { - // When user types a character - onInput: function(e) { - // When we use the native textarea element, we receive an event object - // When we use the masked-input component, we receive the value directly - const value = typeof e === 'object' ? e.target.value : e - this.value = value - this.modified = true - this._checkIfValid({ value }) - }, - - // When field is blurred (un-focused) - onChange: function(e) { - // Only invalidate the field when it blurs - this._checkIfValid({ value: e.target.value, invalidate: true }) - }, - - onBlur: function(e) { - if (!(this.optional && e.target.value === '')) { - this._checkIfValid({ value: e.target.value.trim(), invalidate: true }) - } else if (this.modified && !this.optional) { - this._checkIfValid({ value: e.target.value.trim(), invalidate: true }) - } - this.value = e.target.value.trim() - - if (this.validation === 'dollars') { - let value = Number.isNaN(e.target.value) ? '0' : e.target.value - this.value = formatDollars(this._rawValue(value)) - } - }, - - // - _checkIfValid: function({ - value, - invalidate = false, - showValidationIcon = true, - }) { - const valid = this._isValid(value) - if (this.modified) { - this.validationError = inputValidations[this.validation].validationError - } - - // Show error messages or not - if (valid) { - this.showError = false - } else if (invalidate) { - this.showError = true - } - - if (showValidationIcon) { - this.showValid = this.value != '' && valid - } - - // Emit a change event - emitEvent('field-change', this, { - value: this._rawValue(value), - valid: this._isValid(value), - name: this.name, - watch: this.watch, - }) - }, - - _rawValue: function(value) { - return inputValidations[this.validation].unmask.reduce( - (currentValue, character) => { - return currentValue.split(character).join('') - }, - value - ) - }, - - _validate: function(value) { - return inputValidations[this.validation].match.test(this._rawValue(value)) - }, - - _isValid: function(value) { - let valid = this._validate(value) - if (!this.modified && this.initialErrors && this.initialErrors.length) { - valid = false - } else if (this.optional && value === '') { - valid = true - } else if (!this.optional && value === '') { - valid = false - } - - return valid - }, - }, + mixins: [TextInputMixin], } diff --git a/js/mixins/text_input_mixin.js b/js/mixins/text_input_mixin.js new file mode 100644 index 00000000..1e728ee7 --- /dev/null +++ b/js/mixins/text_input_mixin.js @@ -0,0 +1,173 @@ +import MaskedInput, { conformToMask } from 'vue-text-mask' +import inputValidations from '../lib/input_validations' +import { formatDollars } from '../lib/dollars' +import { emitEvent } from '../lib/emitters' + +export default { + name: 'textinput', + + components: { + MaskedInput, + }, + + props: { + name: String, + validation: { + type: String, + default: () => 'anything', + }, + initialValue: { + type: String, + default: () => '', + }, + initialErrors: { + type: Array, + default: () => [], + }, + paragraph: String, + noMaxWidth: String, + optional: Boolean, + watch: { + type: Boolean, + default: false, + }, + }, + + data: function() { + return { + showError: (this.initialErrors && this.initialErrors.length) || false, + showValid: false, + mask: inputValidations[this.validation].mask, + pipe: inputValidations[this.validation].pipe || undefined, + keepCharPositions: + inputValidations[this.validation].keepCharPositions || false, + validationError: + this.initialErrors.join(' ') || + inputValidations[this.validation].validationError, + value: this.initialValue, + modified: false, + } + }, + + computed: { + rawValue: function() { + return this._rawValue(this.value) + }, + }, + + mounted: function() { + if (this.value) { + this._checkIfValid({ + value: this.value, + invalidate: true, + showValidationIcon: false, + }) + + if (this.mask && this.validation !== 'email') { + const mask = + typeof this.mask.mask !== 'function' + ? this.mask + : mask.mask(this.value).filter(val => val !== '[]') + + this.value = conformToMask(this.value, mask).conformedValue + } + } + }, + + created: function() { + emitEvent('field-mount', this, { + optional: this.optional, + name: this.name, + valid: this._isValid(this.value), + }) + }, + + methods: { + // When user types a character + onInput: function(e) { + // When we use the native textarea element, we receive an event object + // When we use the masked-input component, we receive the value directly + const value = typeof e === 'object' ? e.target.value : e + this.value = value + this.modified = true + this._checkIfValid({ value }) + }, + + // When field is blurred (un-focused) + onChange: function(e) { + // Only invalidate the field when it blurs + this._checkIfValid({ value: e.target.value, invalidate: true }) + }, + + onBlur: function(e) { + if (!(this.optional && e.target.value === '')) { + this._checkIfValid({ value: e.target.value.trim(), invalidate: true }) + } else if (this.modified && !this.optional) { + this._checkIfValid({ value: e.target.value.trim(), invalidate: true }) + } + this.value = e.target.value.trim() + + if (this.validation === 'dollars') { + let value = Number.isNaN(e.target.value) ? '0' : e.target.value + this.value = formatDollars(this._rawValue(value)) + } + }, + + // + _checkIfValid: function({ + value, + invalidate = false, + showValidationIcon = true, + }) { + const valid = this._isValid(value) + if (this.modified) { + this.validationError = inputValidations[this.validation].validationError + } + + // Show error messages or not + if (valid) { + this.showError = false + } else if (invalidate) { + this.showError = true + } + + if (showValidationIcon) { + this.showValid = this.value != '' && valid + } + + // Emit a change event + emitEvent('field-change', this, { + value: this._rawValue(value), + valid: this._isValid(value), + name: this.name, + watch: this.watch, + }) + }, + + _rawValue: function(value) { + return inputValidations[this.validation].unmask.reduce( + (currentValue, character) => { + return currentValue.split(character).join('') + }, + value + ) + }, + + _validate: function(value) { + return inputValidations[this.validation].match.test(this._rawValue(value)) + }, + + _isValid: function(value) { + let valid = this._validate(value) + if (!this.modified && this.initialErrors && this.initialErrors.length) { + valid = false + } else if (this.optional && value === '') { + valid = true + } else if (!this.optional && value === '') { + valid = false + } + + return valid + }, + }, +}