Persist custom url parameters with algolia search url rewriting

1.3k Views Asked by At

We are using vue instantsearch from Algolia.

When the user lands on page with some initial url parameters, algolia instantsearch loads an initial search, and changes the url to include the search parameters. However the initial url parameters do not persist when algolia rewrites the url, and we'd like them to stay. ie.e

  • land on /stuff?myparam=value
  • algolia sets up intial search results and changes url to /stuff?refinementList=... and the url param myparam is removed. Is there a way to keep it in the url?
3

There are 3 best solutions below

0
On

By default Vue InstantSearch overrides the query parameters. You can control what is rendered in the URL through the routing.router option of Vue InstantSearch. You can provide an history router with a custom createURL function. You will be able to keep the "current" parameters in the URL.

0
On

We needed ?lang=[LANG_CODE] such as ?lang=de followed by the algolia stuff.

This is what we came up with: (note the constant ICL_LANGUAGE_CODE which is set to the current language by WPML (WordPress). Keep in mind that it needs NOT to have the ending & sign when there are no parameters in search.

base:

routing: '.$routing.'

where $routing is defined as:

            $routing = 'true'; // For base language
    if( $needs_custom_routing ) {
    $routing = '{
router: instantsearch.routers.history({

/*
  parseURL({ qsModule, location }) { return qsModule.parse(location.search.slice(1)); },
  */
  
createURL({ qsModule, location, routeState }) {
        const { origin, pathname, hash } = location;

        const queryParameters = {};
        if (routeState.query) {
            queryParameters.query = encodeURIComponent(routeState.query);
        }
        if (routeState.categories) {
            queryParameters.categories = routeState.categories.map(encodeURIComponent);
        }
        if (routeState.page !== 1) {
            queryParameters.page = routeState.page;
        }

    const queryString = qsModule.stringify(routeState);
                

    if( queryString ) {
        return `${origin}${pathname}?lang='.ICL_LANGUAGE_CODE.'&${queryString}`;
    } else {
        return `${origin}${pathname}?lang='.ICL_LANGUAGE_CODE.'`;   
    }
    
},      
  
})
} /* /routing */';
} // /needs_custom_routing
1
On

Incredible that there is no simple example to this problem on the whole internet Here is my shot at it (vanilla JS)

const algoliaAppId = 'APP_ID';
const algoliaApiKey = 'API_KEY';
const algoliaIndex = 'instant_search';

const search = instantsearch({
  indexName: algoliaIndex,
  algoliasearch(algoliaAppId, algoliaApiKey),
  routing: {
    router: instantsearch.routers.history({

      createURL({ qsModule, location, routeState }) {
        // current search params 
        const indexState = routeState[algoliaIndex] || {};
        const { origin, pathname, hash, search } = location;
        // grab current query string and convert to object
        const queryParameters = qsModule.parse(search.slice(1)) || {};
        
        // if there is an active search
        if (Object.keys(indexState).length ){
          // merge the search params with the current query params
          Object.assign(queryParameters, routeState);
        }else{
          // remove the search params
          delete queryParameters[algoliaIndex];
        }

        let queryString = qsModule.stringify(queryParameters);

        if(queryString.length){
          queryString = `?${queryString}`;
        }

        return `${origin}${pathname}${queryString}${hash}`;
      },

    })
  }

});

search.start();