Pass Parameter To Algolia React Instant SearchBox - javascript

I am building a website with React and I am using algolia instantsearch on it. I have managed to create a search page which shows all results and filters by search. I want to use an external search input from a different page on the instant search.
What I would like is the search results page to appear already filtered by the search input parameter. I already create a page like (https://url/search/q=name) but the results page isn’t taking the parameter. The instant search displays all the results.
How can I achieve this? Any recommendations or links i can read will be appreciated.
My code looks like this :
import algoliasearch from "algoliasearch/lite";
var url_string = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname + window.location.search;
var url = new URL(url_string);
var q = url.searchParams.get("q");
const searchClient = algoliasearch(
"xxxxxxxxxx",
"xxxxxxxxxxxxxxxxx"
);
function BusinessesSection({ busData }) {
var stateMapping = {
stateToRoute(uiState) {
const indexUiState = uiState['Test'];
return {
query: indexUiState.query,
page: indexUiState.page,
// ...
};
},
routeToState(routeState) {
return {
['Test']: {
query: routeState.query,
page: routeState.page,
// ...
},
};
},
};
const Hit = ({ hit }) => (
<Item.Group divided key={hit.id}>
<Item fluid>
<Item.Header> {hit.name} </Item.Header>
<Item.Description> {hit.business_json.description} </Item.Description>
<Button onClick={() => { handleSingle(hit);}}> View More </Button>
</Item>
</Item.Group>
);
return (
<div>
<InstantSearch
searchClient={searchClient}
indexName="Test"
routing = {
stateMapping = function (uiState) {
return {
q: uiState['Test'].query,
}
},
stateMapping.routeToState = function (routeState) {
return {
query: routeState.q
}
}
}
>
</InstantSearch>
</div>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(BusinessesSection);

To have a default search in a search box, one can use the defaultRefinement parameter on the SearchBox widget of React InstantSearch.
You can add in here the value of your external search input, and then it will work out of the box.
<SearchBox
defaultRefinement={q}
translations={{
placeholder: "Search …"
}}
The defaultRefinement is a string

Related

ReactJS: make a select that load all values from api

I'm creating a select (at the moment i'm using React-Select component) to retrive all the result from the api.
The problem is that API gives me back 20 values, so I should find a method to load other 20 values ( as I make another api call )
const option = personList && personList .map((spl) => {
return {
value: spl.perCod,
label: spl.perName
}
})
<Row>
<Col>
<Select
id="perCod"
name="perCod"
options={option}
/>
</Col>
</Row>
the personList is populated calling the api:
useEffect(() => {
sortEntities();
}, [paginationState.activePage, paginationState.order, paginationState.sort]);
const sortEntities = = () => {
//...
props.getFilteredEntities(
search, // i pass there the parameters for the research
paginationState.activePage - 1,
paginationState.itemsPerPage,
`${paginationState.sort},${paginationState.order}`
),
}
props.getFilteredEntities in my reducer is:
export const getFilteredEntities: ICrudSearchAction<Person> = (search, page, size, sort) => {
const params = new URLSearchParams(search) ? new URLSearchParams(search).toString() : null;
const requestUrl = `${apiUrl}${sort ? `?page=${page}&size=${size}&sort=${sort}` : ''}${sort ? '&' : '?'}${params}`;
return {
type: ACTION_TYPES.FETCH_PERSON_LIST,
payload: axios.get<Person>(`${requestUrl}${sort ? '&' : '?'}cacheBuster=${new Date().getTime()}`),
};
};
At the moment my select has the first 20 results from api. I should need to load others. How can I do? thank you.
change your <Select> code with this,
you have to add option tag within iteration, to render all options within select tag,
<Select id="perCod" name="perCod">
{option.map(o=><option key={Math.random()} value={o.perCod} >{o.perName}</option>)}
</Select>

NextJS - getStaticPaths - Paths seems not bound to one of the params

My Next.js app's pages are provided by an API, each with a uri_prefix and a uri.
The uri_prefix is mandatory, and can be c or s for now. But any letter could be chosen in the end.
It's a pretty simple structure :
pages
|-[prefix]
| |
| |-[slug]
The [slug].jsx page that handles it uses ISG.
So far, the getStaticPath fallback was set to true, so that if an admin creates new pages (eg. {uri_prefix : c, uri : newpage1} & {uri_prefix : s, uri : newpage2}) in the backoffice, ISG generates the static /c/newpage1 and /s/newpage2 file when they are first triggered.
But once generated, trying alt url such as /x/newpage or /whatever/newpage also fires up the page, which is somewhat unexpected (and unwanted). Reading the doc, I thought it would allow only existing prefixes.
Setting fallback to false forbids unwanted urls but also requires a new build of the app, which is not convenient.
I'd like to have /c/newpage1 or /s/newpage2 rendered, but not /c/newpage2 nor /s/newpage1 (nor /somethingelse/newpage* of course). Each page associated with it's own prefix only.
Did I misunderstood how the fallback works ?
Is ther an obvious mistake in the code or is there another way to achieve ISG for new pages without whole build while forbidding unwanted urls ?
Here is the [slug].jsx page :
import Layout from '#/components/Layout';
import SmallCard from '#/components/SmallCard';
import {useRouter} from 'next/router';
export default function src({products, seo}) {
const router = useRouter();
if(router.isFallback) {
return (
<h1>Loading new page...</h1>
)
}
return (
products ? (
<Layout title={seo[0].title} description={seo[0].description}>
<div>
<div className='container-fluid my-5'>
<div className="row justify-content-center">
<h1>{seo[0].h1}</h1>
</div>
<div className="row justify-content-center">
{products.map(
(product)=>(
<SmallCard product = {product}/>
)
)}
</div>
</div>
</div>
</Layout>
) : (
<Layout title={seo[0].title} description={seo[0].description}>
<h1>{seo[0].h1}</h1>
<div dangerouslySetInnerHTML={{__html: seo[0].content_front}}/>
</Layout>
)
)
}
export async function getStaticPaths() {
const resPages = await fetch(`${process.env.API_BASE_URL}/path/to/pagesapi`);
const pages = await resPages.json();
const paths = pages.map((page) => ({
params: {
prefix: page.uri_prefix,
slug: page.uri
},
}))
return {
paths,
fallback: true
};
}
export async function getStaticProps({ params: { slug } }) {
const resPages = await fetch(`${process.env.API_BASE_URL}/path/to/pagesapi`);
const pages = await resPages.json();
const seo=pages.filter(page=> page.uri == slug);
if(seo[0].src) {
const src=seo[0].src;
// get products
const resProducts = await fetch(`${process.env.API_BASE_URL_LEGACY}${src}`);
var products = await resProducts.json();
} else {
var products = null
}
return {
props: {
products,
seo
},
revalidate:60,
};
}
Thanks in advance.

Open a specific tab by matching the browser URL and Tab URL

I have a react component which has a Tab Component in it. This is the component:
import React from 'react';
import { RTabs, I18nText } from '#wtag/react-comp-lib';
import Profiles from './Profiles';
import Search from './Search';
import Booking from './Booking';
const pathName = window.location.href.split('/').reverse()[0];
const features = [
{
tabNum: 0,
title: (
<I18nText
id="features.platform.profiles"
className="platform-features__profiles-tab"
/>
),
content: <Profiles />,
url: '/en-US/p/features/applications/profiles',
},
{
tabNum: 1,
title: (
<I18nText
id="features.platform.search"
className="platform-features__search-tab"
/>
),
content: <Search />,
url: '/en-US/p/features/applications/search',
},
{
tabNum: 2,
title: (
<I18nText
id="features.platform.booking"
className="platform-features__booking-tab"
/>
),
content: <Booking />,
url: '/en-US/p/features/applications/booking',
},
];
const getItems = () => {
return features.map(({ tabNum, title, content, url }, index) => ({
tabNum,
key: index,
title,
content,
url,
}));
};
const PlatformFeatures = () => {
return (
<div className="platform-features__tabs">
<RTabs isVertical={true} items={getItems()} selectedTabKey={2} />
</div>
);
};
export default PlatformFeatures;
When the component is loaded in the browser the first tab is selected and opened by default. While clicking on the respective tabs, the tab opens. The selected tab index number can be passed to selectedTabKey props of the RTabs component and that particular tab will be selected and opened. As seen here index 2 is passed so the 3rd tab i.e: Booking will be selected and opened by default. Now I want to achieve a functionality that the selected tab will be determined by matching the current URL it is in. Like if the URL has booking in it, the Booking tab will be opened while the browser loads the component. It will work like if I give the URL with booking in it to someone and if he pastes that URL in the browser the booking tab will be selected and opened not the default first tab. I think if I can write a function which can determine the browser URL and match it with the urls in the features array and if url matches, it will take the matched tab index from the array and pass it to the selectedTabKey props, then it might open the selected tab dynamically depending on the location of the browser url.selectedTabKey props will always take number as a PropType. I need suggestions and code examples to implement these functionalities.
const browserURL = document.location.pathname;
const filteredURL = features.map(({ url }) => url);
const checkURL = (arr, val) => {
return arr.filter(function(arrVal) {
return val === arrVal;
})[0];
};
const matchedURL = checkURL(filteredURL, browserURL);
const getSelectedTabKey = filteredURL.indexOf(matchedURL);
and then pass the getSelectedTabKey to selectedTabKey props

Reactjs - Passing API data as props for Autocomplete component (Material-UI)

I am a beginner in Reactjs. I am trying to implement the Autocomplete component provided by material-ui. I want to pass the API link as a prop to the element. But how to pass the json label name as a prop to be used in "getOptionLabel"? For example, If we consider this API link which returns TV Show names, we need to use SHOW.NAME to access the name of the show.
getOptionLabel={(option) => option.show.name}
Here, the dynamic part is 'show.name'. How to pass this as prop? I tried doing
const label = 'show.name'
and then
getOptionLabel={(option) => option.label}
But his wouldn't work.
You need to pass the props in the function.
You could do something like this:
export default function App() {
const someData = [{
name: "abc"
}]
return ( <
Autocomplete myOptions={someData} />
);
}
export default function ComboBox(props) {
return ( <
Autocomplete id = "combo-box-demo"
options = {
props.myOptions
}
getOptionLabel = {
(option) => option.name
}
style = {
{
width: 300
}
}
renderInput = {
(params) => < TextField { ...params
}
label = "Combo box"
variant = "outlined" / >
}
/>
);
}
See it live here

Dynamic routing with getServerSideProps in Nextjs

I'm trying to learn nextjs. Struggling to work out routing with getServerSideProps.
Using a free API I have a list of countries displayed on the DOM. I want to dynamically link to a country and data be fetched and displayed for that specific country.
Heres my code so far
const Country = props => (
<Layout>
<h1>{props.country.name}</h1>
<span>{props.country.capital}</span>
</Layout>
);
export async function getServerSideProps(context) {
const { id } = context.query;
const res = await fetch(`https://restcountries.eu/rest/v2/name/${id}`);
const country = await res.json();
console.log(`Fetched place: ${country.name}`);
return { props: { country } };
}
export default Country;
<div className='container'>
<Head>
<title>Countries List</title>
<link rel='icon' href='/favicon.ico' />
</Head>
<Layout>
<main>
<h1>
Countries{' '}
<span role='img' aria-label='world emoji'>
🌎
</span>
</h1>
<ul>
{countries.map(country => (
<li key={country.name}>
<Link href='/p/[id]' as={`/p/${country.name}`}>
<a>{country.name}</a>
</Link>
</li>
))}
</ul>
</main>
</Layout>
</div>
);
export async function getServerSideProps() {
// Call an external API endpoint to get posts.
const res = await fetch('https://restcountries.eu/rest/v2/all');
const countries = await res.json();
// By returning { props: posts }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
countries,
},
};
}
export default Home;
The URL dynamically routes ok. For example, when you click on Afghanistan the URL shows http://localhost:3000/p/Afghanistan.
My country component however doesn't display anything and undefined is printed to the terminal.
Example of URL and response from URL: https://restcountries.eu/rest/v2/name/Afghanistan
{
name: "Afghanistan"
}
Apologies if a noob question. Trying to learn nextjs
export async function getServerSideProps(context) {
const { id } = context.query;
const res = await fetch(`https://restcountries.eu/rest/v2/name/${id}`);
const country = await res.json();
console.log(`Fetched place: ${country.name}`);
return { props: { country } };
}
you are returning a nested object from above function
{ props: { country:country } }
so this prop will be attached to props as like this:
`props.props`
this is how you should implement
const Country = props => (
<Layout>
<h1>{props.props.country.name}</h1>
<span>{props.props.country.capital}</span>
</Layout>
);
UPDATE
In early version of next.js I think updated after version 9, we were not returning from serverside function by using props. As of now correct way of implementation is
return {
props: {
countries,
},
};
Next.js 13 Update
In next.js 13, if you set app directory, components in this directory will be server-rendered components by default. That means everything will be run on the server and we do not need to write specifiacallygetServerSideProps. in "app" directory, if your file name is surrounded by [..id], it means it is a dynamic route. In page.jsx, you can access id like this
export default function ProductPage({ params }) {
return (
<div>
<h1>Product ID: {params.id}</h1>
</div>
);
}
There's nothing wrong in how you're handling the dynamic routing of the page. The issue is that the data returned by the API is an array but your code expects it to be an object. You can retrieve the first item from the array and pass that to the component from getServerSideProps.
export async function getServerSideProps(context) {
const { id } = context.params; // Use `context.params` to get dynamic params
const res = await fetch(`https://restcountries.com/v2/name/${id}`); // Using `restcountries.com` as `restcountries.eu` is no longer accessible
const countryList = await res.json();
const [country] = countryList; // Get first item in array returned from API
return { props: { country } };
}
const Country = ({ country }) => {
console.log(country);
return (
<>
<h1>{country.name}</h1>
<span>{country.capital}</span>
</>
);
};
export default Country;
Just to add to the accepted answer, you could also destructure to make it (imho) more readable. This is entirely optional though
const Country = ({ country }) => (
<Layout>
<h1>{country.name}</h1>
<span>{country.capital}</span>
</Layout>
);

Categories