diff --git a/client/luigi-client.d.ts b/client/luigi-client.d.ts index 1b9aa987bd..f22406ab65 100644 --- a/client/luigi-client.d.ts +++ b/client/luigi-client.d.ts @@ -612,10 +612,19 @@ export type getEventData = () => Context; */ export function getContext(): Context; export type getContext = () => Context; - +/** + * Sets node parameters in Luigi Core. The parameters will be added to the URL. + * @param {Object} params + * @memberof Lifecycle + * @example + * LuigiClient.addNodeParams({luigi:'rocks'}); + * LuigiClient.addNodeParams({luigi:'rocks', false}); + */ +export function addNodeParams(params: NodeParams, keepBrowserHistory: Boolean): void; +export type addNodeParams = (params: NodeParams, keepBrowserHistory: Boolean) => void; /** * Returns the node parameters of the active URL. - * Node parameters are defined like URL query parameters but with a specific prefix allowing Luigi to pass them to the micro frontend view. The default prefix is **~** and you can use it in the following way: `https://my.luigi.app/home/products?~sort=asc~page=3`. + * Node parameters are defined like URL query parameters but with a specific prefix allowing Luigi to pass them to the micro frontend view. The default prefix is **~** and you can use it in the following way: `https://my.luigi.app/home/products?~sort=asc&~page=3`. * * > **NOTE:** some special characters (`<`, `>`, `"`, `'`, `/`) in node parameters are HTML-encoded. * @returns {Object} node parameters, where the object property name is the node parameter name without the prefix, and its value is the value of the node parameter. For example `{sort: 'asc', page: 3}` @@ -656,12 +665,14 @@ export type getCoreSearchParams = () => CoreSearchParams; /** * Sends search query parameters to Luigi core. If it is allowed on node level it will be added to url. * @param {Object} searchParams + * @param {boolean} keepBrowserHistory * @memberof Lifecycle * @example * LuigiClient.addCoreSearchParams({luigi:'rocks'}); + * LuigiClient.addCoreSearchParams({luigi:'rocks', false}); */ -export function addCoreSearchParams(searchParam: CoreSearchParams): void; -export type addCoreSearchParams = (searchParam: CoreSearchParams) => void; +export function addCoreSearchParams(searchParams: CoreSearchParams, keepBrowserHistory: Boolean): void; +export type addCoreSearchParams = (searchParams: CoreSearchParams, keepBrowserHistory: Boolean) => void; /** * Returns the current client permissions as specified in the navigation node or an empty object. For details, see [Node parameters](navigation-parameters-reference.md). diff --git a/client/src/lifecycleManager.js b/client/src/lifecycleManager.js index 237d749fcb..c4ff2fa63b 100644 --- a/client/src/lifecycleManager.js +++ b/client/src/lifecycleManager.js @@ -389,7 +389,8 @@ class LifecycleManager extends LuigiClientBase { return this.currentContext.context; } - /**Returns a list of active feature toggles + /** + * Returns a list of active feature toggles * @returns {Array} a list of feature toggle names * @memberof Lifecycle * @since 1.4.0 @@ -399,9 +400,28 @@ class LifecycleManager extends LuigiClientBase { getActiveFeatureToggles() { return this.currentContext.internal.activeFeatureToggleList; } + + /** + * Sets node parameters in Luigi Core. The parameters will be added to the URL. + * @param {Object} params + * @param {boolean} keepBrowserHistory + * @memberof Lifecycle + * @example + * LuigiClient.addNodeParams({luigi:'rocks'}, true); + */ + addNodeParams(params, keepBrowserHistory = true) { + if (params) { + helpers.sendPostMessageToLuigiCore({ + msg: 'luigi.addNodeParams', + data: params, + keepBrowserHistory + }); + } + } + /** * Returns the node parameters of the active URL. - * Node parameters are defined like URL query parameters but with a specific prefix allowing Luigi to pass them to the micro frontend view. The default prefix is **~** and you can use it in the following way: `https://my.luigi.app/home/products?~sort=asc~page=3`. + * Node parameters are defined like URL query parameters but with a specific prefix allowing Luigi to pass them to the micro frontend view. The default prefix is **~** and you can use it in the following way: `https://my.luigi.app/home/products?~sort=asc&~page=3`. * * > **NOTE:** some special characters (`<`, `>`, `"`, `'`, `/`) in node parameters are HTML-encoded. * @returns {Object} node parameters, where the object property name is the node parameter name without the prefix, and its value is the value of the node parameter. For example `{sort: 'asc', page: 3}` @@ -412,6 +432,7 @@ class LifecycleManager extends LuigiClientBase { getNodeParams() { return this.currentContext.nodeParams; } + /** * Returns the dynamic path parameters of the active URL. * Path parameters are defined by navigation nodes with a dynamic **pathSegment** value starting with **:**, such as **productId**. @@ -441,15 +462,17 @@ class LifecycleManager extends LuigiClientBase { /** * Sends search query parameters to Luigi Core. If they are allowed on node level, the search parameters will be added to the URL. * @param {Object} searchParams + * @param {boolean} keepBrowserHistory * @memberof Lifecycle * @example - * LuigiClient.addCoreSearchParams({luigi:'rocks'}); + * LuigiClient.addCoreSearchParams({luigi:'rocks'}, false); */ - addCoreSearchParams(searchParams) { + addCoreSearchParams(searchParams, keepBrowserHistory = true) { if (searchParams) { helpers.sendPostMessageToLuigiCore({ msg: 'luigi.addSearchParams', - data: searchParams + data: searchParams, + keepBrowserHistory }); } } diff --git a/client/src/luigi-client.js b/client/src/luigi-client.js index 3b5dc7ea94..c2130a1bd2 100644 --- a/client/src/luigi-client.js +++ b/client/src/luigi-client.js @@ -47,6 +47,9 @@ class LuigiClient { getContext() { return lifecycleManager.getContext(); } + addNodeParams(params, keepBrowserHistory) { + return lifecycleManager.addNodeParams(params, keepBrowserHistory); + } getNodeParams() { return lifecycleManager.getNodeParams(); } @@ -59,8 +62,8 @@ class LuigiClient { getCoreSearchParams() { return lifecycleManager.getCoreSearchParams(); } - addCoreSearchParams(searchParams) { - return lifecycleManager.addCoreSearchParams(searchParams); + addCoreSearchParams(searchParams, keepBrowserHistory) { + return lifecycleManager.addCoreSearchParams(searchParams, keepBrowserHistory); } getClientPermissions() { return lifecycleManager.getClientPermissions(); diff --git a/core/src/App.html b/core/src/App.html index cbca927dcc..cd19467a1d 100644 --- a/core/src/App.html +++ b/core/src/App.html @@ -1587,9 +1587,21 @@ iframe.luigi.currentNode.clientPermissions && iframe.luigi.currentNode.clientPermissions.urlParameters ) { - RoutingHelpers.addSearchParamsFromClient(iframe.luigi.currentNode, e.data.data); + const { data, keepBrowserHistory } = e.data; + RoutingHelpers.addSearchParamsFromClient( + iframe.luigi.currentNode, + data, + keepBrowserHistory + ); } } + + if ('luigi.addNodeParams' === e.data.msg) { + if (isSpecialIframe) return; + + const { data, keepBrowserHistory } = e.data; + LuigiRouting.addNodeParams(data, keepBrowserHistory); + } }); // listeners are not automatically removed — cancel diff --git a/core/src/core-api/routing.js b/core/src/core-api/routing.js index 75d113bb69..94844a21cf 100644 --- a/core/src/core-api/routing.js +++ b/core/src/core-api/routing.js @@ -1,5 +1,5 @@ import { LuigiConfig } from '.'; -import { GenericHelpers } from '../utilities/helpers'; +import { GenericHelpers, RoutingHelpers } from '../utilities/helpers'; /** * @name Routing */ @@ -40,18 +40,19 @@ class LuigiRouting { * @memberof Routing * @since 1.16.1 * @param {Object} params + * @param {boolean} keepBrowserHistory * @example - * Luigi.routing().addSearchParams({luigi:'rocks', mario:undefined}); + * Luigi.routing().addSearchParams({luigi:'rocks', mario:undefined}, false); */ - addSearchParams(params) { + addSearchParams(params, keepBrowserHistory) { if (!GenericHelpers.isObject(params)) { console.log('Params argument must be an object'); return; } const url = new URL(location); if (LuigiConfig.getConfigValue('routing.useHashRouting')) { - let [hashValue, givenQueryParamsString] = url.hash.split('?'); - let searchParams = new URLSearchParams(givenQueryParamsString); + const [hashValue, givenQueryParamsString] = url.hash.split('?'); + const searchParams = new URLSearchParams(givenQueryParamsString); this._modifySearchParam(params, searchParams); url.hash = hashValue; if (searchParams.toString() !== '') { @@ -60,19 +61,44 @@ class LuigiRouting { } else { this._modifySearchParam(params, url.searchParams); } - window.history.pushState({}, '', url.href); + + this.handleBrowserHistory(keepBrowserHistory, url.href); LuigiConfig.configChanged(); } - //Adds and remove properties from searchParams - _modifySearchParam(params, searchParams) { + // Adds and remove properties from searchParams + _modifySearchParam(params, searchParams, paramPrefix) { for (const [key, value] of Object.entries(params)) { - searchParams.set(key, value); + const paramKey = paramPrefix ? `${paramPrefix}${key}` : key; + + searchParams.set(paramKey, value); if (value === undefined) { searchParams.delete(key); } } } + + addNodeParams(params, keepBrowserHistory) { + if (!GenericHelpers.isObject(params)) { + console.log('Params argument must be an object'); + return; + } + + const paramPrefix = RoutingHelpers.getContentViewParamPrefix(); + const url = new URL(location); + this._modifySearchParam(params, url.searchParams, paramPrefix); + + this.handleBrowserHistory(keepBrowserHistory, url.href); + LuigiConfig.configChanged(); + } + + handleBrowserHistory(keepBrowserHistory, href) { + if (keepBrowserHistory) { + window.history.pushState({}, '', href); + } else { + window.history.replaceState({}, '', href); + } + } } export const routing = new LuigiRouting(); diff --git a/core/src/utilities/helpers/routing-helpers.js b/core/src/utilities/helpers/routing-helpers.js index 4b21530df6..f4bbbeab5c 100644 --- a/core/src/utilities/helpers/routing-helpers.js +++ b/core/src/utilities/helpers/routing-helpers.js @@ -13,7 +13,7 @@ class RoutingHelpersClass { getLastNodeObject(pathData) { const lastElement = [...pathData.navigationPath].pop(); - return lastElement ? lastElement : {}; + return lastElement || {}; } async getDefaultChildNode(pathData, childrenResolverFn) { @@ -60,8 +60,8 @@ class RoutingHelpersClass { } encodeParams(dataObj) { - let queryArr = []; - for (let key in dataObj) { + const queryArr = []; + for (const key in dataObj) { queryArr.push(encodeURIComponent(key) + '=' + encodeURIComponent(dataObj[key])); } return queryArr.join('&'); @@ -130,14 +130,17 @@ class RoutingHelpersClass { getQueryParam(paramName) { return this.getQueryParams()[paramName]; } + getQueryParams() { const hashRoutingActive = LuigiConfig.getConfigBooleanValue('routing.useHashRouting'); return hashRoutingActive ? this.getLocationHashQueryParams() : this.getLocationSearchQueryParams(); } + getLocationHashQueryParams() { const queryParamIndex = location.hash.indexOf(this.defaultQueryParamSeparator); return queryParamIndex !== -1 ? RoutingHelpers.parseParams(location.hash.slice(queryParamIndex + 1)) : {}; } + getLocationSearchQueryParams() { return location.search ? RoutingHelpers.parseParams(location.search.slice(1)) : {}; } @@ -170,7 +173,7 @@ class RoutingHelpersClass { const hashRoutingActive = LuigiConfig.getConfigValue('routing.useHashRouting'); EventListenerHelpers.addEventListener('message', e => { - if ('refreshRoute' === e.data.msg && e.origin === window.origin) { + if (e.data.msg === 'refreshRoute' && e.origin === window.origin) { const path = hashRoutingActive ? Routing.getHashPath() : Routing.getModifiedPathname(); callback(path); } @@ -198,7 +201,7 @@ class RoutingHelpersClass { return pp + link; } - let route = RoutingHelpers.buildRoute(node, `/${node.pathSegment}`); + const route = RoutingHelpers.buildRoute(node, `/${node.pathSegment}`); return pp + GenericHelpers.replaceVars(route, pathParams, ':', false); } @@ -323,7 +326,7 @@ class RoutingHelpersClass { setFeatureToggles(featureToggleProperty, path) { let featureTogglesFromUrl; - let paramsMap = this.sanitizeParamsMap(this.parseParams(path.split('?')[1])); + const paramsMap = this.sanitizeParamsMap(this.parseParams(path.split('?')[1])); if (paramsMap[featureToggleProperty]) { featureTogglesFromUrl = paramsMap[featureToggleProperty]; @@ -331,7 +334,7 @@ class RoutingHelpersClass { if (!featureTogglesFromUrl) { return; } - let featureToggleList = featureTogglesFromUrl.split(','); + const featureToggleList = featureTogglesFromUrl.split(','); if (featureToggleList.length > 0 && featureToggleList[0] !== '') { featureToggleList.forEach(ft => LuigiFeatureToggles.setFeatureToggle(ft)); } @@ -364,12 +367,12 @@ class RoutingHelpersClass { const actionAndParams = elements[1].split('?'); // length 2 involves parameters, length 1 involves no parameters if (actionAndParams.length === 2 || actionAndParams.length === 1) { - let action = actionAndParams[0]; + const action = actionAndParams[0]; let params = actionAndParams[1]; // parse parameters, if any if (params) { params = params.split('&'); - let paramObjects = []; + const paramObjects = []; params.forEach(item => { const param = item.split('='); param.length === 2 && paramObjects.push({ [param[0]]: param[1] }); @@ -435,7 +438,7 @@ class RoutingHelpersClass { realPath = this.resolveDynamicIntentPath(realPath, intentObject.params); // get custom node param prefixes if any or default to ~ let nodeParamPrefix = LuigiConfig.getConfigValue('routing.nodeParamPrefix'); - nodeParamPrefix = nodeParamPrefix ? nodeParamPrefix : '~'; + nodeParamPrefix = nodeParamPrefix || '~'; realPath = realPath.concat(`?${nodeParamPrefix}`); intentObject.params.forEach(param => { realPath = realPath.concat(Object.keys(param)[0]); // append param name @@ -489,7 +492,7 @@ class RoutingHelpersClass { } prepareSearchParamsForClient(currentNode) { - let filteredObj = {}; + const filteredObj = {}; if (currentNode && currentNode.clientPermissions && currentNode.clientPermissions.urlParameters) { Object.keys(currentNode.clientPermissions.urlParameters).forEach(key => { if (key in LuigiRouting.getSearchParams() && currentNode.clientPermissions.urlParameters[key].read === true) { @@ -500,9 +503,9 @@ class RoutingHelpersClass { return filteredObj; } - addSearchParamsFromClient(currentNode, searchParams) { + addSearchParamsFromClient(currentNode, searchParams, keepBrowserHistory) { if (currentNode && currentNode.clientPermissions && currentNode.clientPermissions.urlParameters) { - let filteredObj = {}; + const filteredObj = {}; Object.keys(currentNode.clientPermissions.urlParameters).forEach(key => { if (key in searchParams && currentNode.clientPermissions.urlParameters[key].write === true) { filteredObj[key] = searchParams[key]; @@ -511,7 +514,7 @@ class RoutingHelpersClass { } }); if (Object.keys(filteredObj).length > 0) { - LuigiRouting.addSearchParams(filteredObj); + LuigiRouting.addSearchParams(filteredObj, keepBrowserHistory); } } } @@ -533,7 +536,7 @@ class RoutingHelpersClass { getPageNotFoundRedirectPath(notFoundPath, isAnyPathMatched = false) { const pageNotFoundHandler = LuigiConfig.getConfigValue('routing.pageNotFoundHandler'); if (typeof pageNotFoundHandler === 'function') { - //custom 404 handler is provided, use it + // custom 404 handler is provided, use it const result = pageNotFoundHandler(notFoundPath, isAnyPathMatched); if (result && result.redirectTo) { return result.redirectTo; diff --git a/core/test/core-api/routing.spec.js b/core/test/core-api/routing.spec.js index 7c86be8f8e..1e54b6ebdb 100644 --- a/core/test/core-api/routing.spec.js +++ b/core/test/core-api/routing.spec.js @@ -1,15 +1,16 @@ +import { afterEach } from 'mocha'; +import { LuigiRouting, LuigiConfig } from '../../src/core-api'; + const chai = require('chai'); const assert = chai.assert; const sinon = require('sinon'); -import { afterEach } from 'mocha'; -import { LuigiRouting, LuigiConfig } from '../../src/core-api'; - describe('Luigi routing', function() { - let globalLocationRef = global.location; + const globalLocationRef = global.location; beforeEach(() => { window.history.pushState = sinon.spy(); + window.history.replaceState = sinon.spy(); sinon.stub(LuigiConfig, 'configChanged'); }); afterEach(() => { @@ -32,13 +33,19 @@ describe('Luigi routing', function() { it('set searchparams', () => { window.state = {}; global.location = 'http://some.url.de'; - LuigiRouting.addSearchParams({ foo: 'bar' }); + LuigiRouting.addSearchParams({ foo: 'bar' }, true); sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/?foo=bar'); }); + it('set searchparams without keeping browser history', () => { + window.state = {}; + global.location = 'http://some.url.de'; + LuigiRouting.addSearchParams({ foo: 'bar' }, false); + sinon.assert.calledWithExactly(window.history.replaceState, window.state, '', 'http://some.url.de/?foo=bar'); + }); it('add search params to searchparams', () => { window.state = {}; global.location = 'http://some.url.de?test=tets'; - LuigiRouting.addSearchParams({ foo: 'bar' }); + LuigiRouting.addSearchParams({ foo: 'bar' }, true); sinon.assert.calledWithExactly( window.history.pushState, window.state, @@ -49,13 +56,13 @@ describe('Luigi routing', function() { it('call addSearchParams with wrong argument', () => { console.log = sinon.spy(); global.location = 'http://some.url.de'; - LuigiRouting.addSearchParams('bar'); + LuigiRouting.addSearchParams('bar', true); sinon.assert.calledWith(console.log, 'Params argument must be an object'); }); it('delete search params from url', () => { window.state = {}; global.location = 'http://some.url.de?luigi=rocks&mario=red'; - LuigiRouting.addSearchParams({ mario: undefined }); + LuigiRouting.addSearchParams({ mario: undefined }, true); sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/?luigi=rocks'); }); }); @@ -84,13 +91,13 @@ describe('Luigi routing', function() { it('add searchparams hash routing', () => { window.state = {}; global.location = 'http://some.url.de/#/'; - LuigiRouting.addSearchParams({ foo: 'bar' }); + LuigiRouting.addSearchParams({ foo: 'bar' }, true); sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/#/?foo=bar'); }); it('add search params to hash routing', () => { window.state = {}; global.location = 'http://some.url.de/#/?test=tets'; - LuigiRouting.addSearchParams({ foo: 'bar' }); + LuigiRouting.addSearchParams({ foo: 'bar' }, true); sinon.assert.calledWithExactly( window.history.pushState, window.state, @@ -101,7 +108,7 @@ describe('Luigi routing', function() { it('add search params to hash routing', () => { window.state = {}; global.location = 'http://some.url.de/#/?~luigi=rocks'; - LuigiRouting.addSearchParams({ foo: 'bar' }); + LuigiRouting.addSearchParams({ foo: 'bar' }, true); sinon.assert.calledWithExactly( window.history.pushState, window.state, @@ -112,20 +119,68 @@ describe('Luigi routing', function() { it('call addSearchParams with wrong argument hash routing', () => { console.log = sinon.spy(); global.location = 'http://some.url.de/#/'; - LuigiRouting.addSearchParams('bar'); + LuigiRouting.addSearchParams('bar', true); sinon.assert.calledWith(console.log, 'Params argument must be an object'); }); it('delete search params from url', () => { window.state = {}; global.location = 'http://some.url.de/#/?luigi=rocks&mario=red'; - LuigiRouting.addSearchParams({ mario: undefined }); + LuigiRouting.addSearchParams({ mario: undefined }, true); sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/#/?luigi=rocks'); }); + }); + describe('modifySearchParam', () => { + beforeEach(() => { + sinon + .stub(LuigiConfig, 'getConfigValue') + .withArgs('routing.useHashRouting') + .returns(false); + }); + afterEach(() => { + sinon.restore(); + }); it('_modifySearchParam', () => { - let searchParams = new URLSearchParams('mario=rocks'); + const searchParams = new URLSearchParams('mario=rocks'); LuigiRouting._modifySearchParam({ test: 'tets', luigi: 'rocks', mario: undefined }, searchParams); assert.equal(searchParams.toString(), 'test=tets&luigi=rocks'); }); + it('_modifySearchParam with paramPrefix', () => { + const searchParams = new URLSearchParams('~mario=rocks'); + LuigiRouting._modifySearchParam({ test: 'tets', luigi: 'rocks' }, searchParams, '~'); + assert.equal(searchParams.toString(), '%7Emario=rocks&%7Etest=tets&%7Eluigi=rocks'); + }); + }); + + describe('addNodeParams', () => { + it('add node Params', () => { + window.state = {}; + global.location = 'http://some.url.de'; + LuigiRouting.addNodeParams({ foo: 'bar' }, true); + sinon.assert.calledWithExactly(window.history.pushState, window.state, '', 'http://some.url.de/?%7Efoo=bar'); + }); + it('add node Params without keeping browser history', () => { + window.state = {}; + global.location = 'http://some.url.de'; + LuigiRouting.addNodeParams({ foo: 'bar' }, false); + sinon.assert.calledWithExactly(window.history.replaceState, window.state, '', 'http://some.url.de/?%7Efoo=bar'); + }); + it('add more node param to existing node params', () => { + window.state = {}; + global.location = 'http://some.url.de?~test=tets'; + LuigiRouting.addNodeParams({ foo: 'bar' }, true); + sinon.assert.calledWithExactly( + window.history.pushState, + window.state, + '', + 'http://some.url.de/?%7Etest=tets&%7Efoo=bar' + ); + }); + it('call addNodeParams with wrong argument', () => { + console.log = sinon.spy(); + global.location = 'http://some.url.de'; + LuigiRouting.addNodeParams('bar', true); + sinon.assert.calledWith(console.log, 'Params argument must be an object'); + }); }); }); diff --git a/docs/luigi-client-api.md b/docs/luigi-client-api.md index 8a6013a28b..8cae0aca08 100644 --- a/docs/luigi-client-api.md +++ b/docs/luigi-client-api.md @@ -237,10 +237,25 @@ Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Gl - **since**: 1.4.0 +#### addNodeParams + +Sets node parameters in Luigi Core. The parameters will be added to the URL. + +##### Parameters + +- `params` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** +- `keepBrowserHistory` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** (optional, default `true`) + +##### Examples + +```javascript +LuigiClient.addNodeParams({luigi:'rocks'}, true); +``` + #### getNodeParams Returns the node parameters of the active URL. -Node parameters are defined like URL query parameters but with a specific prefix allowing Luigi to pass them to the micro frontend view. The default prefix is **~** and you can use it in the following way: `https://my.luigi.app/home/products?~sort=asc~page=3`. +Node parameters are defined like URL query parameters but with a specific prefix allowing Luigi to pass them to the micro frontend view. The default prefix is **~** and you can use it in the following way: `https://my.luigi.app/home/products?~sort=asc&~page=3`. @@ -291,11 +306,12 @@ Sends search query parameters to Luigi Core. If they are allowed on node level, ##### Parameters - `searchParams` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** +- `keepBrowserHistory` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** (optional, default `true`) ##### Examples ```javascript -LuigiClient.addCoreSearchParams({luigi:'rocks'}); +LuigiClient.addCoreSearchParams({luigi:'rocks'}, false); ``` #### getClientPermissions diff --git a/docs/luigi-core-api.md b/docs/luigi-core-api.md index 336d680c61..e2599552d8 100644 --- a/docs/luigi-core-api.md +++ b/docs/luigi-core-api.md @@ -1332,11 +1332,12 @@ In order to delete a search query param you can set the value of the param to un ##### Parameters - `params` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** +- `keepBrowserHistory` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** ##### Examples ```javascript -Luigi.routing().addSearchParams({luigi:'rocks', mario:undefined}); +Luigi.routing().addSearchParams({luigi:'rocks', mario:undefined}, false); ``` **Meta** diff --git a/test/e2e-test-application/src/app/project/project.component.html b/test/e2e-test-application/src/app/project/project.component.html index a0883990a9..2588a6971e 100644 --- a/test/e2e-test-application/src/app/project/project.component.html +++ b/test/e2e-test-application/src/app/project/project.component.html @@ -655,6 +655,20 @@

Navigate

> +
  • + + add node params + + +