can't map fetched data as an input field autocomplete - javascript

I'm trying to capture some suggestions for my input field, i can log them without a problem, but i can't map it and autocomplete on my input type field. trying to understand what i'm doing wrong.
const Lista = () => {
const [search, setSearch] = useState("");
useEffect(() => {
handleSearch();
}, []);
async function handleSearch() {
const response = await fetch("/api/product");
const search = await response.json();
setSearch(search);
console.log(search);
}
if (!search) return <p>Loading</p>;
return (
<>
<section>
<div className="listsContainer">
<div className="cartContainer">
<form className="formContainer" onSubmit={handleSubmit}>
<div className="inputs">
<div>
<label>Product</label>
<input
required
onChange={(e) => setSearch(e.target.value)}
/>
<div>
{search
.filter((item) => {
return search.toLowerCase() === ""
? null
: item.name.toLowerCase().includes(search);
})
.map((item) => (
<div key={item.id}>
<h1>{item.name}</h1>
</div>
))}
</div>

you are mapping 'search' as the response while it contains the user input value.
you should add a new locale state for storing the response and then use it for the mapping.
you should notice that filter is an Array method and will not work on Json. You should filer Object.values(yourJson).
see example bellow:
const Lista = () => {
const [search, setSearch] = useState("");
const [productResponse, setproductResponse] = useState({});
useEffect(() => {
handleSearch();
}, []);
async function handleSearch() {
const response = await fetch("/api/product");
const resToJson= await response.json();
setproductResponse(resToJson);
console.log(resToJson);
}
if (!productResponse) return <p>Loading</p>;
return (
<>
<section>
<div className="listsContainer">
<div className="cartContainer">
<form className="formContainer" onSubmit={handleSubmit}>
<div className="inputs">
<div>
<label>Product</label>
<input
required
onChange={(e) => setSearch(e.target.value)}
/>
<div>
{Object.values(productResponse)?.
.filter((item) => {
return search.toLowerCase() === ""
? null
: item.name.toLowerCase().includes(search);
})

Related

How to not real time filter

I'm building on my practice web app and I'm tried to filter the data from fetched data but it filter real time. My question is how to make it not real time, like when searchbar is empty it will fetch all data but when type a text in searchbar it will fetch data from input text.
Here is my code
const { data, loading, error } = useFetch(BASE_URL)
const [search, setSearch] = useState("")
const [inp, setInp] = useState("")
const handleChange = (e) => {
setSearch(e.target.value)
}
if (loading) return <h1> LOADING...</h1>
if (error) console.log(error)
return (
<div className="App" >
<div className="Container">
<label className='header'>Topic</label>
<div className="Container-searchBar">
<input type="Text" value={search} placeholder="Search . . ." onChange={handleChange}/>
</div>
{data.filter((val) => {
if (search === "") {
return val
}
else if (val.tags.includes(search)) {
return val
}
}).map((post) => {
return
.
My return
.
})}
</div>
</div>
);
I'm new to React and JS so sorry for some bad question.
I did not get what you mean by not real-time filtering.
Your approach is okay, if you would like not to apply to filter immediately, you can apply timeout.
const { data, loading, error } = useFetch(BASE_URL);
const [search, setSearch] = useState("");
const [filteredStates, setFilteredStates] = useState([]);
useEffect(() => {
setFilteredStates(data);
const timer = setTimeout(() => {
const filter = data.filter((state) => {
return state.tags.includes(search);
});
setFilteredStates(filter.length ? filter : data);
}, 300);
return () => clearTimeout(timer);
}, [search, data]);
const handleChange = (e) => {
setSearch(e.target.value);
};
if (loading) return <h1> LOADING...</h1>;
if (error) console.log(error);
return (
<div className="App">
<div className="Container">
<label className="header">Topic</label>
<div className="Container-searchBar">
<input
type="Text"
value={search}
placeholder="Search . . ."
onChange={handleChange}
/>
</div>
{filteredStates.map((post) => {
return;
<></>;
})}
</div>
</div>
);
This is not the complete answer you are looking for, but usually you would have to apply conditional trigger for your filter, such as
const onSearchPress = () => {somehowQueryYourData ...... setSearchState(true)}
However, the problem with the info I gave you so far has an issue which I am currenlty facing :
the setSearchState(true) does not get turned off once you trigger the onSearchPress, which in turn creates a real time filter in the end. Hope you can build-on something from this.

How to display multiple data from state in return function?

I am able to get all the JSON in tptcity. After that, I pass it in setCity(tptcity).
Now I have data in the state named city.
In return I want to display it in Name : {city.name} | Temprature : {city.temp} but it is only displaying one city name and tem[pratrure by random.
How can I make it work so that four city names with their temperature will be shown in HTML?
const [city, setCity] = useState([]);
const [search, setSearch] = useState("");
const [istru, setIstru] = useState(false);
const [cities, setCities] = useState(["Delhi","Dehradun","Kotdwara","Pune"])
var [tpt, setTpt] = useState(null);
if(istru==false)
{
setSearch(search.concat(cities))
setIstru(true);
}
const getCity = async (search) => {
const url = `https://api.openweathermap.org/data/2.5/weather?q=${search}&units=metric&appid=7938d9005e68d8b258a109c716436c91`;
const response = await fetch(url);
const resJson = await response.json();
setTpt({[search]:resJson.name});
const tptcity = resJson.main;
const namecity = resJson.name;
tptcity['name'] = namecity;
setCity(tptcity);
};
const getAllCities = async() => {
cities.map(city => getCity(city))
}
useEffect(() => {
getAllCities();
}, [cities]);
return(
<>
<div className="box">
<div className="inputData">
</div>
<input className="is"></input>
{!city ? (
<p className="errorMsg">Enter City Name</p>
) : (
<div>
<div className="wave -one"></div>
<div className="wave -two"></div>
<div className="wave -three"></div>
<div className="info">
<h3 className="tempmin_max">Name : {city.name} | Temprature : {city.temp} </h3>
</div>
</div>
) }
</div>
</>
)
}```

react update state from children broke component at the same level

I am new to react. I'm trying to update the parent state from the child but i have an error on another component at the the same level of the child one.
that's my code.
RedirectPage.js (parent)
const RedirectPage = (props) => {
const [status, setStatus] = useState("Loading");
const [weather, setWeather] = useState(null);
const [location, setLocation] = useState(null)
const [showLoader, setShowLoader] = useState(true)
const [userId, setUserId] = useState(false)
const [isPlaylistCreated, setIsPlaylistCreated] = useState(false)
const headers = getParamValues(props.location.hash)
const getWeather = () =>{
//fetch data..
//...
//...
.then(response => {
var res = response.json();
return res;
})
.then(result => {
setWeather(result)
setShowLoader(false)
setStatus(null)
setLocation(result.name)
});
})
}
const changeStateFromChild = (value) => {
setIsPlaylistCreated(value)
}
useEffect(() => {
getWeather()
},[]);
return (
<div className="containerRedirectPage">
{showLoader ? (
<div className="wrapperLogo">
<img src={loader}className="" alt="logo" />
</div>)
: (
<div className="wrapperColonne">
<div className="firstRow">
<WeatherCard weatherConditions={weather}/>
</div>
{isPlaylistCreated ? (
<div className="secondRow">
<PlaylistCard />
</div>
) : (
<PlaylistButton userId={userId} headers={headers} weatherInfo={weather} playlistCreated={changeStateFromChild} />
)}
</div>
)}
</div>
)
};
export default RedirectPage;
PlaylistButton.js:
export default function PlaylistButton({userId, headers, weatherInfo, playlistCreated}) {
const buttonClicked = async () => {
// ...some code...
playlistCreated(true)
}
return (
<div className="button-container-1">
<span className="mas">CREA PLAYLIST</span>
<button onClick={buttonClicked} id='work' type="button" name="Hover">CREA PLAYLIST</button>
</div>
)
}
and that's the other component i'm getting the error when i click on button.
WeatherCard.js:
const WeatherCard = ({weatherConditions}) => {
const [weather, setWeather] = useState(null);
const [icon, setIcon] = useState(null);
const getTheIcon = () => {
// code to get the right icon
}
setIcon(x)
}
useEffect(() => {
getTheIcon()
},[]);
return (
<div className="weatherCard">
<div className="headerCard">
<h2>{weatherConditions.name}</h2>
<h3>{Math.floor(weatherConditions.main.temp)}°C</h3>
</div>
<div className="bodyCard">
<h5>{weatherConditions.weather[0].description}</h5>
<img className="weatherIcon" src={icon} alt="aa" />
</div>
</div>
)
};
export default WeatherCard;
the first time i load the redirect page WeatherCard component is right. When i click the button i get this error:
error
Can someone explain me why ?
What is the effect of the setting playlistCreated(true) ?
Does it affects the weatherCondition object ?
If weatherCondition could be undefined at some point you need to check it before using its properties (name, main.temp, and weather)
Update:
The error clearly state that it cannot read name from weather because it's undefined. You have to check it before using the weather object properties.
if (!weatherConditions) {
return <div>Loading...</div> // or something appropriate.
}
return (
<div className="weatherCard">
<div className="headerCard">
<h2>{weatherConditions.name}</h2>
{weatherConditions.main && <h3>{Math.floor(weatherConditions.main.temp)}°C</h3>}
</div>
<div className="bodyCard">
{weatherConditions.weather &&
{weatherConditions.weather.length > 0 &&
<h5>{weatherConditions.weather[0].description}</h5>}
....
)

Why am I unable to map my data in React project?

Ill be changing the key shortly. Using the code below I should be able to load a list of movies from the API and each movie should be linked to it's Provider Link website. using
the upMovieDetail. can anyone help point me in the right direction? I have a feeling it has something to do with the component being re-renderd after the click?
here is the codesandbox if you'd rather try to fix it here.. --
https://codesandbox.io/s/movieapp-searchbar-forked-qv1o6
const key ="fde5ddeba3b7dec3fc1f51852ca0fb95";
const getUpMovieDetail = (movieId) => {
//const [movieId, setMovieId] = useState([]);
const url = `https://api.themoviedb.org/3/movie/${movieId}/watch/providers?api_key=${key}`;
return fetch(url);
};
function UpMovieDetail({ movieItem }) {
const [searchLink, setSearchLink] = useState(null);
useEffect(() => {
getUpMovieDetail(movieItem.id)
.then((res) => res.json())
.then((res) => {
setSearchLink(res?.results?.US?.link);
});
}, [movieItem.id]);
return (
<ul className="flexed-search">
{searchLink.map((item) =>
<div className="poster-container" key={item.id}>
<li className="list-item">
<a target="_blank" rel="noopener noreferrer" href={searchLink}
onclick={((event) => {event.preventDefault()})}>
<img className="image-element" tabIndex="0" alt="movie poster"
title={`--Title: ${item.title}-- --Description:
${item.overview}-- --Vote Average: ${item.vote_average}`}
aria-label={item.title}
src={`https://image.tmdb.org/t/p/w500${item.poster_path}`} />
</a>
<h3 className="posterTitle">{item.title}</h3>
</li>
</div>
)}
</ul>
);
};
const SearchBar = () => {
const [search, setSearch] = useState([]);
const [input, setInput] = useState('');
// Input Field
const onUserInput = ({target}) => {
setInput(target.value);
};
// Api Call
const SearchApi = (event) => {
const aUrl = "https://api.themoviedb.org/3/search/movie?api_key=fde5ddeba3b7dec3fc1f51852ca0fb95";
const newUrl = aUrl +'&query=' + input;
event.preventDefault();
fetch(newUrl)
.then((response) => response.json())
.then((data) => {
setSearch(data.results);
})
.catch((error) => {
console.log('Error!! Data interupted!:', error)
})
};
return (
// Heading
<div>
<div className="container">
<h1>Movie Search Extravaganza!</h1>
{/* Input Field and Button Form */}
<form onSubmit={SearchApi}>
<input value={input} onChange={onUserInput} type="text" className="searchbar" aria-label="searchbar" placeholder="search" required/>
<br></br>
<button type="submit" aria-label="searchbutton" className="searchBtn">Movie Express Search</button>
</form>
<h1 className="row-label" tabIndex="0">Movies Related To Your Search</h1>
</div>
<div className="byName-container">
{search.map((item) => (
<UpMovieDetail key={item.id} movieItem={item} />
))}
</div>
</div>
)};
export default SearchBar;```
[1]: http://codesandbox.io/s/movieapp-searchbar-forked-qv1o6
[2]: https://codesandbox.io/s/movieapp-searchbar-forked-qv1o6
From the first render it throws the error because searchLink is null.
Try this:
{
searchLink && searchLink.length && searchLink.map((item) =>
...
}

using ternary operator with two map

I'm trying to learn react by coding, here i have come up with this code which works ! but only i need to know how to use if else or maybe ternary operator here. What i want to achieve is this: when user comes to the page this is already there :
{sisalto.map(({ avain, value }, index) => (
<div>
<div>
<IndexBox y={avain} />
</div>
<div>
<ValueBox value={value} />
</div>
</div>
))}
and when user writes something on input then this comes instead of the first one:
{searchResults.map(({ avain, value }, index) => (
<div>
<div>
<IndexBox y={avain} />
</div>
<div>
<ValueBox value={value} />
</div>
</div>
))}
my code :
function App() {
const [data, setData] = useState([])
const [searchResults, setSearchResults] = useState([])
const [searchTerm, setSearchTerm] = useState('')
const [sisalto, setSisalto] = useState([])
const fetchData = () => {
let corsAnywhere = 'https://cors-anywhere.herokuapp.com/'
let something = 'http://ksngfr.com/something.txt'
fetch(corsAnywhere + something)
.then(response => response.text())
.then(result => {
const theDataArr = result.replace(/\n/g, ' ')
const f = theDataArr.split(' ')
setData(f)
})
}
useEffect(() => {
fetchData()
}, [searchTerm])
useEffect(() => {
const mappedResult = data.map(d => {
var propertyK = d.split(':')[0]
var propertyv = d.split(':')[1]
return {
avain: propertyK,
value: propertyv
}
})
setSisalto(mappedResult)
const results = mappedResult.filter(each => each.avain === searchTerm)
setSearchResults(results)
}, [data, searchTerm])
console.log(sisalto)
return (
<div>
<header>
<div>
<h1>something</h1>
<input
type="text"
value={searchTerm}
placeholder="Search..."
onChange={e => setSearchTerm(e.target.value)}
/>
</div>
</header>
<div>
{searchResults.map(({ avain, value }, index) => (
<div>
<div>
<IndexBox y={avain} />
</div>
<div>
<ValueBox value={value} />
</div>
</div>
))}
</div>
</div>
)
}
export default App
data i'm fetching :
/* ------------------------
2005-07-09 03:05
1:74539
2:29734
3:95426
4:35489
------------------------ */
You can use Ternary Operator like this
<div>
{
isTrue
? (<div>YEP</div>)
: (<div>NO</div>)
}
</div>
Now you can use React.Fragment to achieve your goal like this -
<div>
{
isTrue
? (<React.Fragment>{/* map */}</React.Fragment>)
: (<React.Fragment>{/* map */}</React.Fragment>)
}
</div>
// React.Fragment shorthand
<div>
{
isTrue
? (<>{/* map */}</>)
: (<>{/* map */}</>)
}
</div>
If you don't want anyting in else statement just let it be null like this
{ isTrue ? <>YEP</> : null }

Categories

Resources