Home > Mobile >  Vanilla JS: Get undefined when calling a function in in-line html
Vanilla JS: Get undefined when calling a function in in-line html

Time:10-05

I get undefined like shown on the picture, when I attach filterByTypes function to onclick on my button. It worked correctly before I started to use webpack. Maybe my syntax is not correct.

enter image description here

function filterByTypes(type) {
      console.log(type)
      getBookmarks(type)
      const buttons = document.querySelectorAll('.button')
      for (let i = 0; i < buttons.length; i  ) {
        if (buttons[i].dataset.id === type) {
          buttons[i].classList.add('highlight')
        } else {
          buttons[i].classList.remove('highlight')
        }
      }
    }
    
    export function generateOptionsAndFilters() {
        for (let i = 0; i < types?.length; i  ) {
          sourceType.innerHTML  = 
          `<option value=${types[i].value}>${types[i].selectName}</option>`
      
          filterStrip.innerHTML  = 
          `<button onclick="${filterByTypes(`${types[i].value}`)}"  data-id=${types[i].value}>${types[i].selectName}</button>`
        }
      }

CodePudding user response:

Template strings are syntax for generating strings.

Inside the template, ${filterByTypes(${types[i].value})} means "Call filterByTypes with the given argument right now and put the return value in the resulting string.

filterByTypes has no return statement, so it returns undefined.


If you want to generate an onclick attribute, then you need to put the JavaScript source code you want in the resulting string instead.

You'll end up with something along the lines of:

onclick="filterByTypes(${escapeHTML(JSON.stringify(types[i].value))})"

Note this uses the escapeHTML function from this answer.

I do not recommend this as it is fragile, has scoping issues, can be vulnerable to XSS attacks, and is hard to debug.


Generating your DOM using DOM methods instead of mashing strings of HTML together is safer.

export function generateOptionsAndFilters() {
    for (let i = 0; i < types?.length; i  ) {

      const option = document.createElement('option').
      option.textContent = types[i].selectName;
      option.value = types[i].value;
      sourceType.appendChild(option);

      const button = document.createElement('button');
      button.className = "button";
      button.setAttribute('data-id', types[i].value);
      button.textContent = types[i].selectName;
      button.addEventListener("click", () => filterByTypes(types[i].value));
      filterStrip.appendChild(button);
    }
  }

CodePudding user response:

Might be additional back ticks. Try this

filterStrip.innerHTML  =  `<button onclick="${filterByTypes(${types[i].value})}"  data-id=${types[i].value}>${types[i].selectName}</button>`
  • Related