diff --git a/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/Router.js b/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/Router.js index 1209a32e10d..e0fb4a44622 100644 --- a/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/Router.js +++ b/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/Router.js @@ -37,6 +37,20 @@ function tryParse(value: ?string) { return parseFloat(value); } +function equalBindings(value1, value2) { + if (typeof(value1) !== 'object' || typeof(value2) !== 'object') { + return value1 == value2; + } + + const objectKeys = Object.keys(value1); + + if (!equal(objectKeys, Object.keys(value2))) { + return false; + } + + return objectKeys.every((key) => equalBindings(value1[key], value2[key])); +} + function addValueToSearchParameters(searchParameters: URLSearchParams, value: Object, path: string) { if (Array.isArray(value)) { addArrayToSearchParameters(searchParameters, value, path); @@ -302,7 +316,7 @@ export default class Router { : this.bindingDefaults.get(key); // Type unsafe comparison to not trigger a new navigation when only data type changes - if (value != observableValue.get()) { + if (!equalBindings(value, observableValue.get())) { observableValue.set(value); } } diff --git a/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/tests/Router.test.js b/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/tests/Router.test.js index 1286e3f22b5..3aaba1225ce 100644 --- a/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/tests/Router.test.js +++ b/src/Sulu/Bundle/AdminBundle/Resources/js/services/Router/tests/Router.test.js @@ -1020,6 +1020,56 @@ test('Binding should not be updated if only data type changes', () => { expect(page.set.mock.calls).not.toContainEqual(['2']); }); +test('Binding should not be updated if the same object is set again', () => { + routeRegistry.getAll.mockReturnValue({ + list: { + name: 'list', + type: 'list', + path: '/list', + attributeDefaults: {}, + }, + }); + + const filter = jest.fn(() => ({ + get: jest.fn().mockReturnValue({}), + set: jest.fn(), + observe: jest.fn(), + intercept: jest.fn(), + }))(); + + const history = createMemoryHistory(); + const router = new Router(history); + router.bind('filter', filter); + + router.navigate('list', {filter: {}}); + expect(filter.set.mock.calls).not.toContainEqual([{}]); +}); + +test('Binding should be updated if another object is set', () => { + routeRegistry.getAll.mockReturnValue({ + list: { + name: 'list', + type: 'list', + path: '/list', + attributeDefaults: {}, + }, + }); + + const filter = jest.fn(() => ({ + get: jest.fn().mockReturnValue({}), + set: jest.fn(), + observe: jest.fn(), + intercept: jest.fn(), + }))(); + + const history = createMemoryHistory(); + const router = new Router(history); + router.bind('filter', filter); + + router.navigate('list', {filter: {test: {eq: 'Test'}}}); + expect(filter.set.mock.calls).toContainEqual([{test: {eq: 'Test'}}]); +}); + test('Navigate to child route using state', () => { const formRoute = extendObservable({}, { name: 'sulu_snippet.form',