From 5521f3b246be4c24cd54f5e0b5383fc9e78e24dd Mon Sep 17 00:00:00 2001 From: Dan Chadwick <dan899@gmail.com> Date: Tue, 26 Apr 2016 19:17:34 -0400 Subject: [PATCH] paper-input: Exposed invalid status via `onInvalid` action. --- addon/components/paper-input.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/addon/components/paper-input.js b/addon/components/paper-input.js index 7ee8d7e64..8bef4386a 100644 --- a/addon/components/paper-input.js +++ b/addon/components/paper-input.js @@ -27,6 +27,7 @@ export default BaseFocusable.extend(ColorMixin, FlexMixin, { tabindex: null, hideAllMessages: false, isTouched: false, + lastIsInvalid: undefined, hasValue: computed('value', 'isNativeInvalid', function() { let value = this.get('value'); @@ -38,8 +39,21 @@ export default BaseFocusable.extend(ColorMixin, FlexMixin, { return `input-${this.get('elementId')}`; }), + /** + * The result of isInvalid is appropriate for controlling the display of + * validation error messages. It also may be used to distinguish whether + * the input would be considered valid after it is touched. + * + * @public + * + * @return {boolean|null} Whether the input is or would be invalid. + * null: input has not yet been touched, but would be invalid if it were + * false: input is valid (touched or not) + * true: input has been touched and is invalid. + */ isInvalid: computed('isTouched', 'validationErrorMessages.length', 'isNativeInvalid', function() { - return this.get('isTouched') && (this.get('validationErrorMessages.length') || this.get('isNativeInvalid')); + let isInvalid = this.get('validationErrorMessages.length') || this.get('isNativeInvalid'); + return isInvalid && !this.get('isTouched') ? null : !!isInvalid; }), renderCharCount: computed('value', function() { @@ -120,6 +134,7 @@ export default BaseFocusable.extend(ColorMixin, FlexMixin, { didReceiveAttrs() { this._super(...arguments); assert('{{paper-input}} and {{paper-select}} require an `onChange` action.', !!this.get('onChange')); + this.notifyInvalid(); }, didInsertElement() { @@ -179,17 +194,27 @@ export default BaseFocusable.extend(ColorMixin, FlexMixin, { return offsetHeight + (line > 0 ? line : 0); }, + notifyInvalid() { + let isInvalid = this.get('isInvalid'); + if (this.get('lastIsInvalid') !== isInvalid) { + this.sendAction('onInvalid', this.get('isInvalid')); + this.set('lastIsinvalid'); + } + }, + actions: { handleInput(e) { this.sendAction('onChange', e.target.value); this.growTextarea(); let inputElement = this.$('input').get(0); this.set('isNativeInvalid', inputElement && inputElement.validity && inputElement.validity.badInput); + this.notifyInvalid(); }, handleBlur(e) { this.sendAction('onBlur', e); this.set('isTouched', true); + this.notifyInvalid(); } } });