fix(select-rich): trigger manual update invoker selected elem on sync
This commit is contained in:
parent
f7ab53910d
commit
1671c705b8
4 changed files with 51 additions and 6 deletions
5
.changeset/tricky-pumpkins-lie.md
Normal file
5
.changeset/tricky-pumpkins-lie.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/select-rich': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix select rich to manually request update for the invoker selected element when it synchronizes, as the modelValue could be changed but would not trigger a change since the old and new value are both referenced from the updated node reference, meaning they will always be the same and never pass the dirty check.
|
||||||
|
|
@ -265,6 +265,13 @@ export class LionSelectRich extends SlotMixin(ScopedElementsMixin(OverlayMixin(L
|
||||||
this._invokerNode.selectedElement = this.formElements[
|
this._invokerNode.selectedElement = this.formElements[
|
||||||
/** @type {number} */ (this.checkedIndex)
|
/** @type {number} */ (this.checkedIndex)
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* Manually update this, as the node reference may be the same, but the modelValue might not.
|
||||||
|
* This would mean that it won't pass the LitElement dirty check.
|
||||||
|
* hasChanged in selectedElement won't work, since the oldValue and the newValue's modelValues will be the same,
|
||||||
|
* as they are referenced through the same node reference.
|
||||||
|
*/
|
||||||
|
this._invokerNode.requestUpdate('selectedElement');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import { LitElement } from '@lion/core';
|
import { LitElement } from '@lion/core';
|
||||||
|
// @ts-expect-error
|
||||||
|
import { renderLitAsNode } from '@lion/helpers';
|
||||||
import { OverlayController } from '@lion/overlays';
|
import { OverlayController } from '@lion/overlays';
|
||||||
|
import { LionOption } from '@lion/listbox';
|
||||||
import {
|
import {
|
||||||
aTimeout,
|
aTimeout,
|
||||||
defineCE,
|
defineCE,
|
||||||
|
|
@ -16,10 +19,6 @@ import '@lion/listbox/lion-option.js';
|
||||||
import '@lion/listbox/lion-options.js';
|
import '@lion/listbox/lion-options.js';
|
||||||
import '../lion-select-rich.js';
|
import '../lion-select-rich.js';
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import('@lion/listbox').LionOption} LionOption
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {LionSelectRich} lionSelectEl
|
* @param {LionSelectRich} lionSelectEl
|
||||||
*/
|
*/
|
||||||
|
|
@ -155,6 +154,40 @@ describe('lion-select-rich', () => {
|
||||||
// @ts-ignore allow protected access in tests
|
// @ts-ignore allow protected access in tests
|
||||||
expect(el._invokerNode.hasAttribute('single-option')).to.be.true;
|
expect(el._invokerNode.hasAttribute('single-option')).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('updates the invoker when the selected element is the same but the modelValue was updated asynchronously', async () => {
|
||||||
|
const tag = defineCE(
|
||||||
|
class LionCustomOption extends LionOption {
|
||||||
|
render() {
|
||||||
|
return html`${this.modelValue.value}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
createRenderRoot() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const tagString = unsafeStatic(tag);
|
||||||
|
|
||||||
|
const firstOption = renderLitAsNode(
|
||||||
|
html`<${tagString} checked .choiceValue=${10}></${tagString}>`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const el = /** @type {LionSelectRich} */ (await fixture(html`
|
||||||
|
<lion-select-rich>
|
||||||
|
${firstOption}
|
||||||
|
<${tagString} .choiceValue=${20}></${tagString}>
|
||||||
|
</lion-select-rich>
|
||||||
|
`));
|
||||||
|
|
||||||
|
// @ts-ignore allow protected access in tests
|
||||||
|
expect(el._invokerNode.shadowRoot.firstElementChild.textContent).to.equal('10');
|
||||||
|
|
||||||
|
firstOption.modelValue = { value: 30, checked: true };
|
||||||
|
await el.updateComplete;
|
||||||
|
// @ts-ignore allow protected access in tests
|
||||||
|
expect(el._invokerNode.shadowRoot.firstElementChild.textContent).to.equal('30');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('overlay', () => {
|
describe('overlay', () => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { expect, fixture as _fixture, html, nextFrame } from '@open-wc/testing';
|
import { aTimeout, expect, fixture as _fixture, html } from '@open-wc/testing';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import '../lion-textarea.js';
|
import '../lion-textarea.js';
|
||||||
|
|
||||||
|
|
@ -159,7 +159,7 @@ describe('<lion-textarea>', () => {
|
||||||
|
|
||||||
const resizeSpy = sinon.spy(textArea, 'resizeTextarea');
|
const resizeSpy = sinon.spy(textArea, 'resizeTextarea');
|
||||||
el.style.display = 'block';
|
el.style.display = 'block';
|
||||||
await nextFrame();
|
await aTimeout(0);
|
||||||
expect(resizeSpy.calledOnce).to.be.true;
|
expect(resizeSpy.calledOnce).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue