Elias Achilles
Elias Achilles

Reputation: 89

How to get this.value as an argument in a function placed in an event handler in JavaScript?

function change_myselect(sel) {
  return new sel;
}


 function customers () {

    var  xmlhttp, myObj, i, tbl = '';

    xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        myObj = JSON.parse(this.responseText);
        tbl += '<table border="1">';
        for (i in myObj) {
          tbl += '<tr><td>' + myObj[i] + '</td></tr>' ;
        }
        tbl += '</table>';
        document.getElementById('showSelection').innerHTML = tbl;
      }
    };

    xmlhttp.open('GET', 'suppliers.txt', true);
    xmlhttp.send();
  }
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>
<h2>Make a table based on the value of a drop down menu.</h2>

<select onchange="change_myselect(customers)">
  <option value="">Choose an option</option>
  <option value="customers">Customers</option>
  <option value="products">Products</option>
  <option value="suppliers">Suppliers</option>
</select>

<p id="showSelection"></p>
In the code above it works because I've written manually CUSTOMERS in the change_myselect function as an argument.

function change_myselect(sel) {
  return  new sel;
}

 function customers () {

    var  xmlhttp, myObj, i, tbl = '';

    xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        myObj = JSON.parse(this.responseText);
        tbl += '<table border="1">';
        for (i in myObj) {
          tbl += '<tr><td>' + myObj[i] + '</td></tr>' ;
        }
        tbl += '</table>';
        document.getElementById('showSelection').innerHTML = tbl;
      }
    };

    xmlhttp.open('GET', 'customers.txt', true);
    xmlhttp.send();
  }
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>
<h2>Make a table based on the value of a drop down menu.</h2>

<select onchange="change_myselect(this.value)">
  <option value="">Choose an option</option>
  <option value="customers">Customers</option>
  <option value="products">Products</option>
  <option value="suppliers">Suppliers</option>
</select>

<p id="showSelection"></p>

I want to make a table based on the value of a drop-down menu. I've used an ONCHANGE event handler to get the value of the option and pass it to the change_myselect function to retrieve the respective information from the server with JSON. When i write the name of the CUSTOMERS function, in the change_myselect function it works fine. But when i use THIS.VALUE, it does not work. I've used the NEW key word to return and call the CUSTOMERS function without using parentheses.

Upvotes: 3

Views: 131

Answers (3)

Andrew Ymaz
Andrew Ymaz

Reputation: 2213

It looks like the issue with code above is that you are referring to

this.value

You could revisit your change_myselect function to expect event as argument and then extract selected value from event, for example:

var change_myselect = function(event) {
  var selectedValue = event && event.target && event.target.value || '';
  return selectedValue || '';
};

make sure that you also modify HTML portion of your code to to pass event as argument as well:

<select onchange="change_myselect(event)">

Also you could store output of change_myselect in another variable to use down the road in your http request logic.

Upvotes: 1

Teemu
Teemu

Reputation: 23406

Everything you get from the HTML is string. When you pass literally written customers to change_myselect function, it's a reference to customers function. When you pass this.value, it's just a string. That's why you get an error instead of a function call.

Based on your code, it looks like you want to call a function which has the same name as the value of the selected option. In JavaScript, strings can't directly be converted to references (in a rational way), which is what you need, when you refer a function. You'd need a helper object to get the reference.

// Helper object contains methods calling the functions
const handlers = {
  customers () {customers();},
  products () {products();},
  suppliers () {suppliers();}
}

function change_myselect(sel) {
  // Check, if the passed property name is a function in handlers object
  if (typeof handlers[sel] === 'function') {
    // A method named as the passed string was found
    // Call the found method
    handlers[sel]();
  }
}

function customers () {
  console.log('customers called');
}
function products () {
  console.log('products called');
}
function suppliers () {
  console.log('suppliers called');
}
<h2>Make a table based on the value of a drop down menu.</h2>

<select onchange="change_myselect(this.value)">
  <option value="">Choose an option</option>
  <option value="customers">Customers</option>
  <option value="products">Products</option>
  <option value="suppliers">Suppliers</option>
</select>

<p id="showSelection"></p>

In change_myselect, the code checks, if the helper object contains a method which has the same name as the passed string. For this we use bracket notation, where the string in the brackets is evaluated as a property of the object before the brackets. If the passed property is found, the code calls the method in handlers object, using the bracket notation again. Notice the parenthesis at the end of the line. The helper method then calls the actual function, which does the job.

If you've customer function to call only, then just leave the methods referring to the other functions out from the helper object. You can also simplify the code by placing the code of the functions to the methods of handlers object directly.

Upvotes: 2

Stratos Vetsos
Stratos Vetsos

Reputation: 11

You actually don't use your select's value anywhere or performing any xhr request. Try changing your js code to something like this:

 function performXhr(entity) {
      var xmlhttp,
        myObj,
        i,
        tbl = "";

      xmlhttp = new XMLHttpRequest();
      xmlhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          myObj = JSON.parse(this.responseText);
          tbl += '<table border="1">';
          for (i in myObj) {
            tbl += "<tr><td>" + myObj[i] + "</td></tr>";
          }
          tbl += "</table>";
          document.getElementById("showSelection").innerHTML = tbl;
        }
      };

      xmlhttp.open("GET", `${entity}.txt`, true);
      xmlhttp.send();
    }

and your HTML markup

    <select onchange="performXhr(this.value)">
      <option value="">Choose an option</option>
      <option value="customers">Customers</option>
      <option value="products">Products</option>
      <option value="suppliers">Suppliers</option>
    </select>

Upvotes: 1

Related Questions