diff --git a/web/client/plugins/featuregrid/FeatureEditor.jsx b/web/client/plugins/featuregrid/FeatureEditor.jsx
index 935efab545..5367d50239 100644
--- a/web/client/plugins/featuregrid/FeatureEditor.jsx
+++ b/web/client/plugins/featuregrid/FeatureEditor.jsx
@@ -28,6 +28,15 @@ import {gridTools, gridEvents, pageEvents, toolbarEvents} from './index';
const EMPTY_ARR = [];
const EMPTY_OBJ = {};
+/**
+ * Custom check for filterRenderers useMemo function
+ * @param {object} prevProps previous props
+ * @param {object} nextProps next props
+ * @returns {boolean}
+ */
+export const checkFilterRendererProps = (prevProps, nextProps) => {
+ return isEqual(prevProps.describe, nextProps.describe) && isEqual(prevProps.fields, nextProps.fields);
+};
const Dock = connect(createSelector(
getDockSize,
@@ -187,7 +196,9 @@ const FeatureDock = (props = {
};
const items = props?.items ?? [];
const toolbarItems = items.filter(({target}) => target === 'toolbar');
- const filterRenderers = useMemo(() => getFilterRenderers(props.describe, props.fields), [props.describe, props.fields]);
+ // ensure to avoid re-rendering of the feature grid (lost focus on every render) in any case if for some
+ // reason the describeFeatureType or fields are generated but equal.
+ const filterRenderers = useMemo(() => getFilterRenderers(props.describe, props.fields), checkFilterRendererProps);
return (
{ props.onSizeChange(size, dockProps); }}>
diff --git a/web/client/plugins/featuregrid/__tests__/FeatureEditor-test.jsx b/web/client/plugins/featuregrid/__tests__/FeatureEditor-test.jsx
index d8e399fdb7..44b56b4534 100644
--- a/web/client/plugins/featuregrid/__tests__/FeatureEditor-test.jsx
+++ b/web/client/plugins/featuregrid/__tests__/FeatureEditor-test.jsx
@@ -1,6 +1,6 @@
import expect from 'expect';
-import {selector } from '../FeatureEditor';
+import {selector, checkFilterRendererProps } from '../FeatureEditor';
describe('FeatureEditor plugin component', () => {
@@ -104,6 +104,25 @@ describe('FeatureEditor plugin component', () => {
expect(result.fields).toEqual(FIELDS);
});
});
+ describe('utility functions', () => {
+ it('checkFilterRendererProps', () => {
+ // check if the function returns true if the props are the same
+ expect(checkFilterRendererProps({
+ describe: {},
+ fields: []
+ }, {
+ describe: {},
+ fields: []
+ })).toBe(true);
+ expect(checkFilterRendererProps({
+ describe: {},
+ fields: []
+ }, {
+ describe: {},
+ fields: [{name: 'name', type: 'string'}]
+ })).toBe(false);
+ });
+ });
});
diff --git a/web/client/selectors/__tests__/featuregrid-test.js b/web/client/selectors/__tests__/featuregrid-test.js
index 471e6e25cb..b983659525 100644
--- a/web/client/selectors/__tests__/featuregrid-test.js
+++ b/web/client/selectors/__tests__/featuregrid-test.js
@@ -671,6 +671,20 @@ describe('Test featuregrid selectors', () => {
}
};
expect(selectedLayerFieldsSelector(state)).toEqual([FIELD]);
+ // check that fields are memoized when applying defaults
+ const stateEmptyFields = {
+ featuregrid: {
+ selectedLayer: 'TEST_LAYER'
+ },
+ layers: {
+ flat: [{
+ id: "TEST_LAYER",
+ title: "Test Layer",
+ name: 'editing:polygons.test'
+ }]
+ }
+ };
+ expect(selectedLayerFieldsSelector(stateEmptyFields)).toBe(selectedLayerFieldsSelector(stateEmptyFields));
});
it('editingAllowedGroupsSelector', () => {
const editingAllowedGroups = ['test'];
diff --git a/web/client/selectors/featuregrid.js b/web/client/selectors/featuregrid.js
index b9856e6de8..e7f6fc3ac5 100644
--- a/web/client/selectors/featuregrid.js
+++ b/web/client/selectors/featuregrid.js
@@ -112,7 +112,7 @@ export const getTitleSelector = state => {
const title = getTitle(getLayerById(state, selectedLayerIdSelector(state)));
return isObject(title) ? title[currentLocaleSelector(state)] || title.default || '' : title;
};
-
+const STANDARD_FIELDS = [];
/**
* Returns the current selected layer (featuregrid) fields, if any.
* @param {*} state
@@ -120,7 +120,7 @@ export const getTitleSelector = state => {
*/
export const selectedLayerFieldsSelector = state => {
const layer = getLayerById(state, selectedLayerIdSelector(state));
- const fields = get(layer, "fields", []);
+ const fields = get(layer, "fields", STANDARD_FIELDS);
return fields;
};
export const getCustomizedAttributes = state => {