diff --git a/packages/field/src/FormatMixin.js b/packages/field/src/FormatMixin.js index a9d813204..a63fcef44 100644 --- a/packages/field/src/FormatMixin.js +++ b/packages/field/src/FormatMixin.js @@ -230,7 +230,7 @@ export const FormatMixin = dedupeMixin( // imperatively, we DO want to format a value (it is the only way to get meaningful // input into `.inputElement` with modelValue as input) - if (this.__isHandlingUserInput && this.errorState) { + if (this.__isHandlingUserInput && this.errorState && this.inputElement) { return this.inputElement ? this.value : undefined; } return this.formatter(this.modelValue, this.formatOptions); @@ -335,8 +335,6 @@ export const FormatMixin = dedupeMixin( // is guaranteed to be calculated setTimeout(this._reflectBackFormattedValueToUser); }; - this.inputElement.addEventListener(this.formatOn, this._reflectBackFormattedValueDebounced); - this.inputElement.addEventListener('input', this._proxyInputEvent); this.addEventListener('user-input-changed', this._onUserInputChanged); // Connect the value found in to the formatting/parsing/serializing loop as a // fallback mechanism. Assume the user uses the value property of the @@ -347,16 +345,26 @@ export const FormatMixin = dedupeMixin( this._syncValueUpwards(); } this._reflectBackFormattedValueToUser(); + + if (this.inputElement) { + this.inputElement.addEventListener( + this.formatOn, + this._reflectBackFormattedValueDebounced, + ); + this.inputElement.addEventListener('input', this._proxyInputEvent); + } } disconnectedCallback() { super.disconnectedCallback(); - this.inputElement.removeEventListener('input', this._proxyInputEvent); this.removeEventListener('user-input-changed', this._onUserInputChanged); - this.inputElement.removeEventListener( - this.formatOn, - this._reflectBackFormattedValueDebounced, - ); + if (this.inputElement) { + this.inputElement.removeEventListener('input', this._proxyInputEvent); + this.inputElement.removeEventListener( + this.formatOn, + this._reflectBackFormattedValueDebounced, + ); + } } }, ); diff --git a/packages/field/test/FormatMixin.test.js b/packages/field/test/FormatMixin.test.js index 1c7905364..aa004ca70 100644 --- a/packages/field/test/FormatMixin.test.js +++ b/packages/field/test/FormatMixin.test.js @@ -1,7 +1,7 @@ import { expect, fixture, html, aTimeout, defineCE, unsafeStatic } from '@open-wc/testing'; import sinon from 'sinon'; -import { LionLitElement } from '@lion/core/src/LionLitElement.js'; +import { LitElement } from '@lion/core'; import { Unparseable } from '@lion/validate'; import { FormatMixin } from '../src/FormatMixin.js'; @@ -17,7 +17,7 @@ describe('FormatMixin', () => { before(async () => { const tagString = defineCE( - class extends FormatMixin(LionLitElement) { + class extends FormatMixin(LitElement) { render() { return html` @@ -176,6 +176,14 @@ describe('FormatMixin', () => { expect(el.inputElement.value).to.equal('foo: test2'); }); + it('works if there is no underlying inputElement', async () => { + const tagNoInputString = defineCE(class extends FormatMixin(LitElement) {}); + const tagNoInput = unsafeStatic(tagNoInputString); + expect(async () => { + await fixture(html`<${tagNoInput}>`); + }).to.not.throw(); + }); + describe('parsers/formatters/serializers', () => { it('should call the parser|formatter|serializer provided by user', async () => { const formatterSpy = sinon.spy(value => `foo: ${value}`);