diff --git a/changelogs/upcoming/7473.md b/changelogs/upcoming/7473.md new file mode 100644 index 00000000000..f77971bcc99 --- /dev/null +++ b/changelogs/upcoming/7473.md @@ -0,0 +1,3 @@ +**Bug fixes** + +- Fixed `EuiTextArea` to correctly fire `onChange` callbacks on clear button click diff --git a/src/components/form/text_area/text_area.spec.tsx b/src/components/form/text_area/text_area.spec.tsx index 0170b856709..a2ca9acc43e 100644 --- a/src/components/form/text_area/text_area.spec.tsx +++ b/src/components/form/text_area/text_area.spec.tsx @@ -26,23 +26,46 @@ describe('EuiTextArea', () => { }); it('works for controlled components', () => { + const onChange = cy.stub(); const ControlledTextArea = ({}) => { const [value, setValue] = useState(''); - return ( - setValue(e.target.value)} - isClearable - /> - ); + onChange.callsFake((e) => { + setValue(e.target.value); + }); + return ; }; cy.realMount(); cy.get('textarea').type('hello world'); - cy.get('textarea').should('have.value', 'hello world'); + cy.get('textarea') + .should('have.value', 'hello world') + .then(() => { + expect(onChange).to.have.callCount(11); + }); cy.get('[data-test-subj="clearTextAreaButton"]').click(); - cy.get('textarea').should('have.value', ''); + cy.get('textarea') + .should('have.value', '') + .then(() => { + expect(onChange).to.have.callCount(12); + }); + }); + + it('manually fires an onInput event', () => { + const onInput = cy.stub(); + cy.realMount(); + + cy.get('textarea') + .type('1') + .then(() => { + expect(onInput).to.have.callCount(1); + }); + + cy.get('[data-test-subj="clearTextAreaButton"]') + .click() + .then(() => { + expect(onInput).to.have.callCount(2); + }); }); }); }); diff --git a/src/components/form/text_area/text_area.tsx b/src/components/form/text_area/text_area.tsx index d3253dc1742..fb1e95074c2 100644 --- a/src/components/form/text_area/text_area.tsx +++ b/src/components/form/text_area/text_area.tsx @@ -106,13 +106,22 @@ export const EuiTextArea: FunctionComponent = (props) => { return { onClick: () => { if (ref.current) { - ref.current.value = ''; + // Updates the displayed value and fires `onChange` callbacks + // @see https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-onchange-event-in-react-js + const nativeValueSetter = Object.getOwnPropertyDescriptor( + window.HTMLTextAreaElement.prototype, + 'value' + )!.set!; + nativeValueSetter.call(ref.current, ''); + const event = new Event('input', { bubbles: true, cancelable: false, }); ref.current.dispatchEvent(event); - ref.current.focus(); // set focus back to the textarea + + // Set focus back to the textarea + ref.current.focus(); } }, 'data-test-subj': 'clearTextAreaButton',