Reputation: 3
I need a little help with my project. I think it is almost done, but I don't know how to finish...
So, I want to build app with input, select and button. Into input u can write for example, mettalica and after click on button app renders list with all songs, titles and tabTypes(guitar tabs). The problem is that i want to get info from select and render only that songs which includes for example player tabs.
Sandbox Code: https://codesandbox.io/s/react-example-ys6py?fontsize=14&hidenavigation=1&theme=dark
class Search extends React.Component {
state = {
searchValue: "",
songs: [],
musicTabs: [
'Dowolne',
'Bass',
'Player',
'Chords',
'Guitar'
],
result: ''
};
handleOnChange = event => {
this.setState({ searchValue: event.target.value });
};
handleSelectChange = (event) => {
this.setState({
result: event.target.value
})
console.log(this.state.result)
}
handleSearch = () => {
this.makeApiCall(this.state.searchValue);
};
makeApiCall = async searchInput => {
let api_url = `https://www.songsterr.com/a/ra/songs/byartists.json?artists=${searchInput}`;
const response = await fetch(api_url);
const songs = await response.json();
this.setState({ songs });
};
render() {
return (
<div>
<Header />
<input
name="text"
type="search"
placeholder="Search..."
onChange={event => this.handleOnChange(event)}
value={this.state.SearchValue}
/>
<Select optionValue={ this.state.musicTabs } change={ this.handleSelectChange } value={ this.state.result } />
<br />
<button onClick={this.handleSearch}>Search</button>
{this.state.songs ? (
<div>
{
this.state.songs.map((song, index) => (
<div key={index} className="lists">
<h1>Artist: <span>{song.artist.name}</span></h1>
<h2>Song title: <span>{song.title}</span></h2>
<ol>
<b>Available tabs:</b>
{song.tabTypes.map((tab, index) =>
<li key={index}> {song.tabTypes[index]} </li>
)}
</ol>
</div>
))
}
</div>
) : (
<p>Something</p>
)}
</div>
);
}
}
const Select = (props) => {
const { optionValue, change } = props;
const valueMusicTabs = optionValue.map((musicTab, index) => {
return <option name={ optionValue[index] } key={ index }> { optionValue[index] } </option>
})
return (
<>
<select onChange={ change }>
{ valueMusicTabs }
</select>
</>
)
};
Thanks for help guys!
Upvotes: 0
Views: 384
Reputation: 4748
I checked the codesandbox, everything was working right. this.setState
is an asynchronous function. So, if you will console.log
after this.setState
chances are your will not log updated value. You can do it like this with a callback function.
handleSelectChange = (event) => {
this.setState({
result: event.target.value
}, () => console.log(this.state.result))
}
If you want to filter
you can do that by making a function like:
filterSongs = selected => {
return songs.filter(song => song.tabTypes === selected);
}
and After that modify your handleSelectChange
as:
handleSelectChange = (event) => {
let songs = filterSongs(event.target.value);
this.setState({
result: event.target.value,
toDisplay: songs
}, () => console.log(this.state.result))
}
and finally in your JSX
:
return (
<>
{toDisplay.map((song, index) => {
return <p key={index}>{song.toString()}</p>
})}
</>
);
Upvotes: 0
Reputation: 3
Thanks for answers! I have last question, where I have to use method to filter that rendered list. If I select "Player" I want to render only that songs, which inlcudes "Player" tab in tabTypes. I still can't get it. I can't do it by changing API link.
Upvotes: 0
Reputation: 2955
If I understand correctly. you want to get the results from API based on selected values of input
and select
.
as I can see you are only passing the param from input nothing from select.
handleSearch = () => {
this.makeApiCall(this.state.searchValue);
};
makeApiCall = async searchInput => {
let api_url = `https://www.songsterr.com/a/ra/songs/byartists.json?artists=${searchInput}`;
const response = await fetch(api_url);
const songs = await response.json();
this.setState({ songs });
};
The new call will be
let api_url = `https://www.songsterr.com/a/ra/songs/byartists.json?artists=${searchInput}&tabTypes=${selectValue}`;
I do not know how what are the parameters this API accepts.
Upvotes: 0
Reputation: 503
I think you did everything right, just used the wrong prop
<Select optionValue={ this.state.musicTabs } onChange={ this.handleSelectChange } value={ this.state.result } />
the change
prop on the Select
component should just be changed to onChange
since it's a default event it will be passed with the event to your handleChange
method
Upvotes: 1