From ecea6999a5465872f08b16baf98f29ccefde6a78 Mon Sep 17 00:00:00 2001 From: Nikola Stojanovic <68916411+dzonidoo@users.noreply.github.com> Date: Thu, 30 Jan 2025 13:00:37 +0100 Subject: [PATCH] Fix onChange on TreeSelelect (#907) --- .../components/TreeSelect/TreeSelect.tsx | 15 ++++++++++- examples/pages/components/TreeSelect.tsx | 25 ++++++++----------- package-lock.json | 2 +- package.json | 2 +- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/app-typescript/components/TreeSelect/TreeSelect.tsx b/app-typescript/components/TreeSelect/TreeSelect.tsx index 75e8898a..96eb416f 100644 --- a/app-typescript/components/TreeSelect/TreeSelect.tsx +++ b/app-typescript/components/TreeSelect/TreeSelect.tsx @@ -96,6 +96,13 @@ export class TreeSelect extends React.Component, IState> { private popperInstance: Instance | null; private zIndex: number = getNextZIndex(); + /* + * This variable is used to distinguish changes coming from outside (from props.value) + * from those made by the user through interaction with the component. + * It prevents triggering `onChange` when `props.value` updates externally. + */ + private changesFromOutside: boolean; + constructor(props: IProps) { super(props); this.state = { @@ -133,6 +140,7 @@ export class TreeSelect extends React.Component, IState> { this.treeSelectRef = React.createRef(); this.popperInstance = null; this.onDragEnd = this.onDragEnd.bind(this); + this.changesFromOutside = false; } inputFocus = () => { @@ -212,8 +220,13 @@ export class TreeSelect extends React.Component, IState> { componentDidUpdate(prevProps: Readonly>, prevState: Readonly>): void { if (!isEqual(prevState.value, this.state.value)) { - this.props.onChange(this.state.value); + if (this.changesFromOutside) { + this.changesFromOutside = false; + } else { + this.props.onChange(this.state.value); + } } else if (!isEqual(prevProps.value, this.props.value)) { + this.changesFromOutside = true; this.setState({ value: this.props.value ?? [], }); diff --git a/examples/pages/components/TreeSelect.tsx b/examples/pages/components/TreeSelect.tsx index 774e9fee..69cf69dc 100644 --- a/examples/pages/components/TreeSelect.tsx +++ b/examples/pages/components/TreeSelect.tsx @@ -12,7 +12,7 @@ interface IState { arr: any; } -let options = [ +const multiSelectOptions = [ { value: {name: 'Category1'}, children: [ @@ -93,7 +93,7 @@ let options = [ }, ] -let options2 = [ +const singleSelectOptions = [ { value: {name: 'Category1', border: 'red'}, children: [ @@ -169,9 +169,6 @@ let options2 = [ }, ] -let fetchedArr = []; -fetch('https://nominatim.openstreetmap.org/search/berlin?format=json&addressdetails=1&limit=20').then(response => response.json()).then(data => fetchedArr = data); - type ICancelFn = () => void; function searchOptions( @@ -181,9 +178,7 @@ function searchOptions( let timeout = setTimeout(() => { callback( - fetchedArr - .filter((item: any) => item.display_name.toLocaleLowerCase().includes(term.toLocaleLowerCase())) - .map((item) => ({value: item})), + multiSelectOptions.filter((item: any) => item.value.name.toLocaleLowerCase().includes(term.toLocaleLowerCase())) ); }, 1000); @@ -198,8 +193,8 @@ export class TreeSelectDocs extends React.Component<{}, IState> { this.state = { value: [], value2: [], - options: options, - options2: options, + options: multiSelectOptions, + options2: multiSelectOptions, inputValue: '', arr: [] } @@ -244,7 +239,7 @@ export class TreeSelectDocs extends React.Component<{}, IState> { options} + getOptions={() => multiSelectOptions} getId={(item) => item.name} getLabel={(item) => item.name} selectBranchWithChildren @@ -300,7 +295,7 @@ export class TreeSelectDocs extends React.Component<{}, IState> { options} + getOptions={() => multiSelectOptions} getId={(item) => item.name} getLabel={(item) => item.name} selectBranchWithChildren @@ -358,8 +353,8 @@ export class TreeSelectDocs extends React.Component<{}, IState> { display_name} - getId={({display_name}) => display_name} + getLabel={({name}) => name} + getId={({name}) => name} selectBranchWithChildren allowMultiple searchOptions={searchOptions} @@ -400,7 +395,7 @@ export class TreeSelectDocs extends React.Component<{}, IState> { options2} + getOptions={() => singleSelectOptions} getLabel={(item) => item.name} getId={(item) => item.name} getBorderColor={(item) => item.border} diff --git a/package-lock.json b/package-lock.json index acd3ff2c..f8d53638 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "superdesk-ui-framework", - "version": "4.0.13", + "version": "4.0.14", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0d858110..b1ca41c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "superdesk-ui-framework", - "version": "4.0.13", + "version": "4.0.14", "license": "AGPL-3.0", "repository": { "type": "git",