Configure Widget not accepting query value on search.start()

Hi All,

I’m migrating search from v3 to v4 but I’ve encountered an issue regarding the searchParameters option and new configure widget. Previously we had the a function that checked the url for a query string, if it was present it would apply the value to the search widget and the page would load with the results of that value. Now however, when using the configure widget nothing is passed to my search widget when a query string is present. Below is a snippet of my function to get the query string value and what my configure widget looks like.

function getUrlQuery(name = '') {
 const query = document.location.search.match(RegExp(`${name}=([^&]+)`, 'i'));
 let val = query && query[1] ? decodeURIComponent(query[1]) : '';
 val = val.replace(/[\+<>=\/\\]/gi, ' ').trim(); // replace unwanted chars with a space
 return val;
}

search.addWidgets([
   configure({
       hitsPerPage: 10,
   	   query: getUrlQuery()
   }),
])

Hi Brendan,

I am guessing that you are using instantsearch.js here.
I cannot find anything obviously wrong with the piece of code you attached. Maybe you could provide us a codesandbox replicating your issue by forking this one: https://codesandbox.io/s/github/algolia/doc-code-samples/tree/master/InstantSearch.js/getting-started

By the way, I am wondering if you have considered implementing the url sync as detailed in this guide: https://www.algolia.com/doc/guides/building-search-ui/going-further/routing-urls/js/
(here is a live example)
This is the recommended way to keep the browser url synced with the search state so I would encourage you to implement this behaviour as specified in this documentation.

Thomas

Hi Thomas,

I had a look through the documentation and examples and have implemented the routing helper. The only issue is I can’t find a way to return a dynamic index object with the correct values through the routeToState() method inside the stateMapping array on line 116 inside search-routing,js. I can assign the index I’m currently using to the stateToRoute() method above but that’s it. Can you think of any way for me to pass the value from the stateToRoute() method to the routeToState()?

Hi @brendan.betheldo,
Thanks for the code sandbox.

I modified your sandbox slightly here: https://codesandbox.io/s/routing-test-g4p4v
If I understand your question correctly, it solves your problem.
If you simply do like this:

const index = "instant_search";
const object = {
  [index]: {
    a: 1
  }
};

console.log(object);
=>
{
  instant_search: {
    a: 1
  }
}

It is called Computed property name: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names

Please let me know how it goes on your side and if you have any question.
Have a nice week.

Hi @eunjae.lee, I attempted something similar but my logic must have been off. @thomas.dalous recommended using the url-sync to keep the browser synced with search. Why is this the recommended way? It seems to add a fair bit more code to the app.

Previously I was just checking the query params in the url then using that to search the index then when a user entered a query I was syncing that to the url using window.location.history.

Lastly, in the example I was following instantsearch was being used globally but I’m using imports inside my app and the only way for me to access routers was to import instantsearch like the following;
import instantsearch from 'instantsearch.js/dist/instantsearch.production.min';

Then I import instant search from search-routing.js into my search.js.

EDIT: I can see in the example @thomas.dalous gave that a whole bunch of extra functionality is being done that I don’t need. I’ve added the the stateMapping object inside the routing option inside where I declare search and it works perfectly.

  routing: {
	stateMapping: {
		stateToRoute(uiState) {
			const index = state.indexName;
			const indexUiState = uiState[index] || {};
			// refer to uiState docs for details: https://www.algolia.com/doc/api-reference/widgets/ui-state/js/
			return {
				query: indexUiState.query
			};
		},
		routeToState(routeState) {
			// refer to uiState docs for details: https://www.algolia.com/doc/api-reference/widgets/ui-state/js/
			const index = state.indexName
			return {
				// eslint-disable-next-line camelcase
				[index]: {
					query: routeState.query
				}
			};
		}
	}
},

Thanks @eunjae.lee and @thomas.dalous for all your help!

1 Like

Hi @brendan.betheldo
With url sync, when the UI changes, it will change the url.
Or if the url changes, it will change the UI.
They affect each other which makes the smoother UX.
For example, when something on the UI changes, it will update the url.
User can copy the url for later use, or send it to friends.
If we don’t have url sync, user will copy the initial url which doesn’t reflect the current UI state.

I hope this makes sense with you.
Let me know if you have any other question.