0

Browser Console Error

Uncaught ReferenceError: getNewCars is not defined at HTMLDivElement.onclick

Code Explained

I'm building a car selector form. How it works is there's categories (known as seasons) that can be clicked on to bring up a list of specific cars that pertain to that category (season).

Html

<div class="chooseCar">

    <div class="chooseCarTabs">
    
    </div>

    <div class="chooseCarWrapper">
        <div id="chooseCarSelection">
        
        </div>
    </div>
</div>

<script src="/public/theme/scripts/car-selection.js"></script>

car-selection.js

alert('new car-selection js')
let cars;
let seasons = [
  {
    "name": "Seasonal Cars",
    "path": "seasonal.json"
  },
  {
    "name": "Modern Cars",
    "path": "modern.json"
  },
  {
    "name": "Classic Cars",
    "path": "classic.json"
  },
  {
    "name": "Flag Cars",
    "path": "flags.json"
  }
];
let seasonTab = "Seasonal Cars";

const chooseCarBody = document.getElementById('chooseCarSelection');
const seasonsTabs = document.getElementsByClassName('chooseCarTabs')[0];

function loadCars(){
  chooseCarBody.innerHTML = '';
  cars.forEach(car => {
    chooseCarBody.innerHTML += `
        <div class="singleCar">
          <div class="singleCarInner">
            <img src="/public/images/avatars/${car.filename}" alt="${car.name}">
          </div>
        </div>
      `
  })
}

//Ajax Request
async function setSeasons() {
  seasonsTabs.innerHTML = ''
  await seasons.forEach(season => {
    seasonsTabs.innerHTML += `
        <div ${seasonTab == season.name ? 'class="activeSeasonTab"' : ''} onclick="getNewCars('${season.name}', '${season.path}' )">
          ${season.name}
        </div>
      `
  });
}

//Will be replaced with AJAX Request
async function getNewCars(seasonName, season = seasons[0].path){
  cars = null;
  await fetch(`/public/data/cars/${season}`)
      .then(response => response.json())
      .then(data => {
        console.log(data)
        seasonTab = seasonName;
        cars = data;  console.log(cars)
      })
      .catch(error => console.log(error));
  await loadCars()
}

async function initData(){
  await setSeasons();
  await getNewCars(seasons[0].name);
}

initData();

Extra code explanation

let cars; and let seasons work as a state of sorts. When a seasons tab is clicked on an ajax request is sent to get fill the cars state with cars for the category which is then looped through and populated on the page.

My Problem

When I reload the page the cars and category (season) tabs appear on the page just fine including the getNewCars(). But when I go to click on:

<div 
 ${seasonTab == season.name ? 'class="activeSeasonTab"' : ''} 
 onclick="getNewCars('${season.name}', '${season.path}' )"
>
 ${season.name}
</div>

I get this error:

Uncaught ReferenceError: getNewCars is not defined at HTMLDivElement.onclick

Note, inline scripts I don't seem to get this error:

<div class="chooseCar">

    <div class="chooseCarTabs">
    
    </div>

    <div class="chooseCarWrapper">
        <div id="chooseCarSelection">
        
        </div>
    </div>
</div>

<script> /* All scripts in here*/</script>

How do I fix this and what's going wrong with my code that when import from another js file this happens?

Kyle Corbin Hurst
  • 917
  • 2
  • 10
  • 26
  • You're trying to access the function before its declaration. Instead, look into event delegation. store the element via a querySelector and use addEventListener method to attach your function call. – Martin Oct 04 '21 at 18:52
  • @Martin What do you mean? The function is defined when the page is loaded, and isn't called until the user clicks on something. – Barmar Oct 04 '21 at 19:05
  • Why is `setSeasons` an async function? There's nothing asynchronous in it. – Barmar Oct 04 '21 at 19:08
  • `loadCars` also has nothing asynchronous. The only asynchronous function you're calling is `fetch()` from `getNewCars()`. – Barmar Oct 04 '21 at 19:09
  • Are you updating the DOM, generating new "season tab" divs? Because if that's the case, they will not have a reference to the function anymore (because it's after page load). Inline function calls resolves this issue as you also noted yourself, because you're manually giving them the reference each time. In that case you need to look into event delegation. https://stackoverflow.com/questions/34896106/attach-event-to-dynamic-elements-in-javascript – Martin Oct 04 '21 at 19:12
  • @Barmar that's an error on my part. Set seasons were originally being set by an AJAX request as well. the `loadCars` were just making sure the cars loaded after the `cars` state was populated from fetch – Kyle Corbin Hurst Oct 04 '21 at 19:15
  • 1
    @Martin Event delegation isn't needed when you're using inline `onclick="..."` attributes. – Barmar Oct 04 '21 at 19:19
  • @Martin Event delegation is the solution for it not calling the function at all, it makes no sense in this case where it's saying that the function isn't defined. – Barmar Oct 04 '21 at 19:19
  • Also to add, I'm unsure what would change the event delegation by moving the inline scripts into an external script, because the script works fine when it's embedded in the HTML. – Kyle Corbin Hurst Oct 04 '21 at 19:21
  • @Barmar first line `Uncaught ReferenceError: getNewCars is not defined at HTMLDivElement.onclick`. secondly OP mentions that the error doesn't occur when he is utilizing inline scripts, making me believe he has a solution, utilizing inline scripts, but maybe wants something that's not executed inline. Another quote from OP: `Note, inline scripts I don't seem to get this error:` – Martin Oct 04 '21 at 19:43

0 Answers0