0

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!

4 Answers 4

1

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

Sign up to request clarification or add additional context in comments.

Comments

0

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>
    })}
  </>
);

4 Comments

Thanks for answer! 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.
@tomsoon95 Answer Updated
Where exactly I have to modify my JSX?
Could You please modify this in SandBox?
0

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.