fix(select): set formattedValue to text of selected option
This commit is contained in:
parent
26b2f4e0e5
commit
09ee55cbee
4 changed files with 65 additions and 25 deletions
6
.changeset/large-mails-roll.md
Normal file
6
.changeset/large-mails-roll.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
'@lion/form-integrations': patch
|
||||||
|
'@lion/select': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Set formattedValue to the text of the selected option instead of its value
|
||||||
|
|
@ -54,7 +54,7 @@ describe('Form Integrations', () => {
|
||||||
favoriteFruit: 'Banana',
|
favoriteFruit: 'Banana',
|
||||||
favoriteMovie: 'Rocky',
|
favoriteMovie: 'Rocky',
|
||||||
favoriteColor: 'hotpink',
|
favoriteColor: 'hotpink',
|
||||||
lyrics: '1',
|
lyrics: 'Fire up that loud',
|
||||||
range: 2.3,
|
range: 2.3,
|
||||||
terms: [],
|
terms: [],
|
||||||
notifications: '',
|
notifications: '',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
/* eslint-disable max-classes-per-file */
|
/* eslint-disable max-classes-per-file */
|
||||||
import { LionField } from '@lion/form-core';
|
import { LionField } from '@lion/form-core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import('@lion/localize/types/LocalizeMixinTypes').FormatNumberOptions} FormatOptions
|
||||||
|
*/
|
||||||
class LionFieldWithSelect extends LionField {
|
class LionFieldWithSelect extends LionField {
|
||||||
/** @type {any} */
|
/** @type {any} */
|
||||||
static get properties() {
|
static get properties() {
|
||||||
|
|
@ -28,19 +31,19 @@ class LionFieldWithSelect extends LionField {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LionSelectNative: wraps the native HTML element select
|
* LionSelect: wraps the native HTML element select
|
||||||
*
|
*
|
||||||
* <lion-select-native>
|
* <lion-select>
|
||||||
* <label slot="label">My Input</label>
|
* <label slot="label">My Input</label>
|
||||||
* <select slot="input">
|
* <select slot="input">
|
||||||
* <option value="top">top</option>
|
* <option value="top">top</option>
|
||||||
* <option value="bottom">bottom</option>
|
* <option value="bottom">bottom</option>
|
||||||
* </select>
|
* </select>
|
||||||
* </lion-select-native>
|
* </lion-select>
|
||||||
*
|
*
|
||||||
* You can preselect an option by setting the property modelValue.
|
* You can preselect an option by setting the property modelValue.
|
||||||
* Example:
|
* Example:
|
||||||
* <lion-select-native modelValue="${'<value of option 2>'}">
|
* <lion-select .modelValue="${'<value of option 2>'}">
|
||||||
*
|
*
|
||||||
* It extends LionField so it inherits required and disabled.
|
* It extends LionField so it inherits required and disabled.
|
||||||
*
|
*
|
||||||
|
|
@ -59,24 +62,6 @@ export class LionSelect extends LionFieldWithSelect {
|
||||||
this._inputNode.addEventListener('change', this._proxyChangeEvent);
|
this._inputNode.addEventListener('change', this._proxyChangeEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: For some reason we have to override this FormatMixin getter/setter pair for the tests to pass
|
|
||||||
get value() {
|
|
||||||
return (this._inputNode && this._inputNode.value) || this.__value || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't delegate, because we want to preserve caret position via _setValueAndPreserveCaret
|
|
||||||
/** @type {string} */
|
|
||||||
set value(value) {
|
|
||||||
// if not yet connected to dom can't change the value
|
|
||||||
if (this._inputNode) {
|
|
||||||
this._inputNode.value = value;
|
|
||||||
/** @type {string | undefined} */
|
|
||||||
this.__value = undefined;
|
|
||||||
} else {
|
|
||||||
this.__value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param {import('@lion/core').PropertyValues } changedProperties */
|
/** @param {import('@lion/core').PropertyValues } changedProperties */
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
super.updated(changedProperties);
|
super.updated(changedProperties);
|
||||||
|
|
@ -99,6 +84,28 @@ export class LionSelect extends LionFieldWithSelect {
|
||||||
this._inputNode.removeEventListener('change', this._proxyChangeEvent);
|
this._inputNode.removeEventListener('change', this._proxyChangeEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override FormatMixin - set formattedValue to selected option text
|
||||||
|
* @param {*} v - modelValue: can be an Object, Number, String depending on the
|
||||||
|
* input type(date, number, email etc)
|
||||||
|
* @returns {string} formattedValue
|
||||||
|
*/
|
||||||
|
formatter(v) {
|
||||||
|
// The selectedIndex is not yet updated
|
||||||
|
const found = Array.from(this._inputNode.options).find(option => option.value === v);
|
||||||
|
return found ? found.text : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override FormatMixin - set value equal to modelValue instead of formattedValue
|
||||||
|
*/
|
||||||
|
_reflectBackFormattedValueToUser() {
|
||||||
|
if (this._reflectBackOn()) {
|
||||||
|
// Text 'undefined' should not end up in <input>
|
||||||
|
this.value = typeof this.modelValue !== 'undefined' ? this.modelValue : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @protected */
|
/** @protected */
|
||||||
_proxyChangeEvent() {
|
_proxyChangeEvent() {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import { expect, fixture } from '@open-wc/testing';
|
import '@lion/select/define';
|
||||||
|
import { aTimeout, expect, fixture } from '@open-wc/testing';
|
||||||
import { html } from 'lit/static-html.js';
|
import { html } from 'lit/static-html.js';
|
||||||
|
|
||||||
import '@lion/select/define';
|
/**
|
||||||
|
* @typedef {import('../src/LionSelect').LionSelect} LionSelect
|
||||||
|
*/
|
||||||
|
|
||||||
describe('lion-select', () => {
|
describe('lion-select', () => {
|
||||||
it('can preselect an option', async () => {
|
it('can preselect an option', async () => {
|
||||||
|
|
@ -17,6 +20,30 @@ describe('lion-select', () => {
|
||||||
expect(lionSelect.querySelector('select')?.value).to.equal('nr2');
|
expect(lionSelect.querySelector('select')?.value).to.equal('nr2');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets the values correctly based on the option value and view value', async () => {
|
||||||
|
const lionSelect = /** @type {LionSelect} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<lion-select label="Foo item" .modelValue="${'nr2'}">
|
||||||
|
<select slot="input">
|
||||||
|
<option value="nr1">Item 1</option>
|
||||||
|
<option value="nr2">Item 2</option>
|
||||||
|
<option value="nr3"></option>
|
||||||
|
</select>
|
||||||
|
</lion-select>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
expect(lionSelect.serializedValue).to.equal('nr2');
|
||||||
|
expect(lionSelect.formattedValue).to.equal('Item 2');
|
||||||
|
lionSelect.modelValue = 'nr1';
|
||||||
|
await aTimeout;
|
||||||
|
expect(lionSelect.serializedValue).to.equal('nr1');
|
||||||
|
expect(lionSelect.formattedValue).to.equal('Item 1');
|
||||||
|
lionSelect.modelValue = 'nr3';
|
||||||
|
await aTimeout;
|
||||||
|
expect(lionSelect.serializedValue).to.equal('nr3');
|
||||||
|
expect(lionSelect.formattedValue).to.equal('');
|
||||||
|
});
|
||||||
|
|
||||||
it('is accessible', async () => {
|
it('is accessible', async () => {
|
||||||
const lionSelect = await fixture(html`
|
const lionSelect = await fixture(html`
|
||||||
<lion-select .modelValue="${'nr2'}">
|
<lion-select .modelValue="${'nr2'}">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue