skip to Main Content

I am working on a music library where I want the user to be able to filter through choices of songs. I have a backend API where song objects were created title, artist, album, genre, release date. I was able to create 2 dropdowns where the first dropdown allows the user to choose what category they want to filter by e.g. Album. the second dropdown is supposed to allow the user to to make a choice based on the category chosen, but I have duplicates there. I obviously do not want duplicates.

import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {

  const [songs, setSongs] = useState([])

  const [title, setTitle] = useState('')
  
  const [artist, setArtist] = useState('')

  const [album, setAlbum] = useState('')

  const [genre, setGenre] = useState('')
  
  const [date, setDate] = useState('')

  const [category, setCategory] = useState('')

  const [choice, setChoice] =useState([])

  useEffect(() => {
    getAllSongs()
  }, []);

  async function getAllSongs() {
    const response = await axios.get('http://127.0.0.1:8000/api/music/');
    const allSongs = response.data
    setSongs(allSongs)
  }

  async function postSong(event){
    event.preventDefault()
    // const songObject = {'title': title, 'artist': artist, 'album': album, 'release_date': date, 'genre': genre}
    const songObject = {title, artist, album, 'release_date': date, genre}
    await axios.post('http://127.0.0.1:8000/api/music/', songObject)
  }

  const handleTitleChange = (event) => {
    setTitle(event.target.value)
  }

  const handleArtistChange = (event) => {
    setArtist(event.target.value)
  }

  const handleAlbumChange = (event) => {
    setAlbum(event.target.value)
  }

  const handleGenreChange = (event) => {
    setGenre(event.target.value)
  }

  const handleDateChange = (event) => {
    setDate(event.target.value)
  }

  const handleCategoryChange = (event) => {
    setCategory(event.target.value)
  }
  
  const handleChoiceChange = (event) => {
    setChoice(songs.filter((song) => song[category] === event.target.value))
  }

  const displaySongs = (songsArr) => {
    return songsArr.map((song) =>(
      <tr>
        <td>{song?.title}</td>
        <td>{song?.artist}</td>
        <td>{song?.album}</td>
        <td>{song?.genre}</td>
        <td>{song?.release_date}</td>
      </tr>
      ))
  }

  // As a developer, I want to display the data (song title, album, artist, genre, and release date) from the API within a table on the frontend. 

  return (
    <div>
        <h1>Music Library</h1>
        <label for='songs'>Filter: </label>
        <select name='categories' value={category} onChange={handleCategoryChange}>
          <option value="">Select your category</option>
          <option value='title'>Title</option>
          <option value='artist'>Artist</option>
          <option value='genre'>Genre</option>
          <option value='album'>Album</option>
          <option value='release_date'>Release Date</option>
        </select>
        <select name='choice' onChange={handleChoiceChange}>
          <option value="">Select the {category}</option>
          {songs.map((song) => (
           <option>{song[category]}</option>
          ))}
        </select>
        <table>
          <tr>
            <th>Title</th>
            <th>Artist</th>
            <th>Album</th>
            <th>Genre</th>
            <th>Release Date</th>
          </tr>
          {choice.length > 0 ? displaySongs(choice): displaySongs(songs)}
        </table>
        <form>
          <label>Title </label>
          <input type='text' onChange={(event) => handleTitleChange(event)}/>
          {/* <input type='text' onChange={function(event) {return handleTitleChange(event)}}/> */}
          <label> Artist </label>
          <input type='text' onChange={(event) => handleArtistChange(event)}/>
          <label> Album </label>
          <input type='text' onChange={(event) => handleAlbumChange(event)}/>
          <label> Genre </label>
          <input type='text' onChange={(event) => handleGenreChange(event)}/>
          <label> Release Date </label>
          <input type='date' onChange={(event) => handleDateChange(event)}/>
          {/* <input type='submit'value='Add New Song'/> */}
          <button onClick={(event) => postSong(event)} >Add New Song</button>
        </form>
    </div>
  );
}

export default App;


2

Answers


  1. You need to extract unique categories from an array of objects (songs) you have from the server and provide it as a list of options to your second dropdown. There are multiple ways in JavaScript how you can do this. The most straight-forward would be create a new array const categories = [] and use songs.forEach() loop (read docs) to iterate over songs. And in a callback push category to a categories array checking if it’s not yet there. Also you could check Array.reduce() (read more) for a possible solution.
    But I would go with the following:

    const songs = [
      { name: "Billy Jean", category: "pop" },
      { name: "Black and White", category: "pop" },
      { name: "Smells Like Teen Spirit", category: "rock" },
      { name: "I Love Rock'n'roll", category: "rock" },
      { name: "Enter Sandman", category: "metal" },
    ];
    
    const categories = [...(new Set(songs.map(song => song.category)))];
    
    console.log(categories);
    Login or Signup to reply.
  2. Filtering can be used to retrieve a song related to a particular category.
    Try it:

      <select name='choice' onChange={handleChoiceChange}>
        <option value="">Select the {category}</option>
           {songs
              .filter(x => x.category === category)
              .map((song) => (
                   <option value={song.name}>{song.name} -- {song.category} 
                   </option>
            ))}
      </select>
    

    if you want to set a default value on the second dropdown
    const [category, setCategory] = useState(‘title’)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search