0

I am trying to fill the second selector based on the first selector.

My goal is to add all the titles of tracks that are under the artist that is selected.

What is going wrong is that if I put artistValue in console log I get the right value but if I use it to sort on the artist for getting tracks I get this error Cannot convert undefined or null to object

My HTML

<select onchange="Update()" id="artistSelector"></select>
<select id="trackSelector"></select>

My Javascript

    // Get json file
       const url = './jukebox.json';
       const request = new XMLHttpRequest();
       request.open('GET', url, true);

    // activates when the first selector value is changed / onchange="Update()"
    function Update() {
        // Gives value Krezip or Cure but can have more options in the future.
        let artistValue = document.getElementById("artistSelector").value;
        const select = document.querySelector('#trackSelector');
        const data = JSON.parse(request.responseText);
        const entries = Object.entries(data.Albums[artistValue].tracks.title);

        for (const [tracks] of entries) {
            const option = document.createElement('option');
            option.textContent = artist;
            option.value = artist;
            select.appendChild(option);
        }
    }

My JSON

    {
      "Albums": {
        "Krezip": [
          {
            "artist":"Krezip",
            "tracks": [
              {
                "title":"Lost without you",
              },
              {
                "title":"I would stay",
              }
            ]
          }
        ],
        "Cure": [
          {
            "artist":"The Cure",
            "tracks": [
              {
                "title":"A Forest",
              },
              {
                "title":"Lullaby",
              }
            ]
          }
        ]
      }
    }
Robin
  • 11
  • 4

1 Answers1

1

I made a working javascript here dealing with your data described as the json you showed, so that the first dropdown is populated with artists coming from there and when you select a given artist, the second dropdown (trackSelector) gets populated with tracks coming from the selected artist.

I changed your data so that .Albums isn't an array of objects since your example only had arrays with 1 item only. In case you needed Albums to be an actual array having a list of albums holding a collection of tracks, I guess the code would need to change so that trackSelector gets populated with the joined set of tracks coming from all those albums.

const data =
{
  "Albums": {
    "Krezip": 
      {
        "artist":"Krezip",
        "tracks": [
          {
            "title":"Lost without you",
          },
          {
            "title":"I would stay",
          }
        ]
      }
    ,
    "Cure": 
      {
        "artist": "The Cure",
        "tracks": [
          {
            "title":"A Forest",
          },
          {
            "title":"Lullaby",
          }
        ]
      }
    
  }
}

//on document ready
document.addEventListener('DOMContentLoaded', ()=>{
  //populate the dropdown #artistSelector with options coming from data .Albums keys
  Object.keys(data.Albums).forEach((o,i)=>{
    const artistOption = document.createElement('option');
    artistOption.innerText = o;
    artistOption.value = o;
    document.getElementById("artistSelector").appendChild(artistOption);      
  });
  //add the change event listener bound to the update function
  document.getElementById("artistSelector").addEventListener('change', update);
});

//on #artistSelector change event
function update(event) {     

  //remove all the option in the trackSelector dropdown
  document.querySelectorAll('select#trackSelector option').forEach((o,i)=>{o.remove()});

  //fetch relevant information from data according to the selected artist
  const artistValue = event.target.value;          
  const albums = data.Albums[artistValue];    
  
  //fill the trackSelector dropdown with options coming from the tracks of the artist selected
  for (const track of albums.tracks) {
    const option = document.createElement('option');
    option.textContent = track.title;
    option.value = track.title;
    document.getElementById('trackSelector').appendChild(option);  
  }
}
<label for="artistSelector">Artist:</label>
<select id="artistSelector">
  <option value=""></option>
</select>

<label for="trackSelector">Track:</label>
<select id="trackSelector">
  <option value=""></option>
</select>
Diego D
  • 6,156
  • 2
  • 17
  • 30
  • When I try that I get "is not iterable" but in my situation I get it from an external JSON is it possible to have an external JSON and just make it into a javascript thing like what you are doing with const data? – Robin Jul 07 '22 at 14:18
  • Yes.. read here how https://stackoverflow.com/questions/19706046/how-to-read-an-external-local-json-file-in-javascript – Diego D Jul 07 '22 at 14:29
  • but that requires that json to be defined as a string assigned to a variable. Alternatively, if you can serve that json as response from an http request, you could fetch its value with an ajax request. But if you have a local file that you need to read and put its content in a var still somehow I need to think harder . I’ll be more helpful later when I’ll be on my desk.. if in the meantime anyone wants to help I hope they will feel free. – Diego D Jul 07 '22 at 14:36
  • Anyway please tell me more about this json file you have. Is this whole html page being served from local? Or on web server? And the json file is an asset that you mean to include as a reference in the html? I’m asking now because at first I made some assumptions but it’s actually important to know those details to go exactly on spot with no overthinking – Diego D Jul 07 '22 at 15:02
  • just local via inteliji and the json should be a separate file not in the html file itself. I hope that explains what I am trying to do. – Robin Jul 07 '22 at 15:08
  • I thought this would work ```const url = './jukebox.json'; const request = new XMLHttpRequest(); request.open('GET', url, true); const data = JSON.parse(request.responseText);``` – Robin Jul 07 '22 at 15:37
  • yes but it would work only if the application is hosted on web server ... otherwise XMLHttpRequest won't work for local files. That's why I asked the conditions. And it's not clear yet. Anyway if the json file get served by a web server (instead of localhost) the strategy will work – Diego D Jul 08 '22 at 06:29