JavaScript: using onchange to filter data using a drop-down menu

Viewed 67

My goal is filter data based on a user's selection in a drop-down menu.

SET UP

I have an array of objects named employees. First, I sort by the salary attribute, then using another function manipulateData(), I filter by role attribute (which the user selects via a drop-down menu).

(notice in the HTML file that the manipulateData() function is called onchange)

Here is my code:

JavaScript:

let employees = [
    {
        id : 1,
        name : 'John Smith',
        role : 'Sales',
        salary : 100000
    },

    {
        id : 2,
        name : 'Mary Jones',
        role : 'Finance',
        salary : 78000,
    },

    {
        id : 3,
        name : 'Philip Lee',
        role : 'Finance',
        salary : 160000,
    },

    {
        id : 4,
        name : 'Susan Williams',
        role : 'Sales',
        salary : 225000,
    },

    {
        id : 5,
        name : 'Jason Alexander',
        role : 'Finance',
        salary : 90000,
    },

     {
        id : 6,
        name : 'Derek Sanders',
        role : 'Sales',
        salary : 140000,
    }

]

// #########################################

function filterData() {
    let allData = employees;

    let selectBox = document.getElementById("employee-role");
    let selectedValue = selectBox.options[selectBox.selectedIndex].value;

    // SORT SALARIES DESCENDING
    allData.sort(function (a, b) {
        return b.salary - a.salary;
    })

    console.log('Sorted Data', allData);

    // *** Here is where I'd like to invoke the dataManipulation() function to filter on only the user-selected roles

    // LIMIT TO ONLY 2 RECORDS
    let filteredData = allData.filter( (value, index) => {
        return (index < 2);
    });


    // RENDER THE CHART
    //renderChart(filteredData);
}

function manipulateData(filteredData) {
    return filteredData.filter(e => e.role === selectedValue)
}

HTML:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="description" content="">
        <title>Example</title>

    </head>
    <body>

    <div class="container-fluid">

        <!-- header -->
        <div class="row justify-content-center">
            <div class="align-self-center">
                <h1>Example</h1>
            </div>
        </div>

        <!-- drop down menu -->
        <div class="row justify-content-center">
            <div class="align-self-center">
                <div class="user-control">
                    <div class="form-group">
                        <select id="employee-role" class="form-control" onchange="manipulateData()">
                            <option value="All">All Roles</option>
                            <option value="Sales">Sales</option>
                            <option value="Finance">Finance</option>
                        </select>
                    </div>
                </div>
            </div>
        </div>


        <!-- container of bar chart -->
        <div id="chart-area"></div>

    </div>
    </body>
</html>

Question: before I reduce the size of the data set to 2 records, how would I incorporate the manipulateData() function to grab only the role selected by the user via the drop-down menu?

Thanks! (JavaScript newbie here)

2 Answers

You can call manipulateData(allData, selectedValue) directly with your data set. After this, you can remove onchange="manipulateData()" in your HTML.

let employees = [{
    id: 1,
    name: 'John Smith',
    role: 'Sales',
    salary: 100000
  },
  {
    id: 2,
    name: 'Mary Jones',
    role: 'Finance',
    salary: 78000,
  },
  {
    id: 3,
    name: 'Philip Lee',
    role: 'Finance',
    salary: 160000,
  },
  {
    id: 4,
    name: 'Susan Williams',
    role: 'Sales',
    salary: 225000,
  },
  {
    id: 5,
    name: 'Jason Alexander',
    role: 'Finance',
    salary: 90000,
  },
  {
    id: 6,
    name: 'Derek Sanders',
    role: 'Sales',
    salary: 140000,
  }
]

function filterData() {
  let allData = employees;

  let selectBox = document.getElementById("employee-role");
  let selectedValue = selectBox.options[selectBox.selectedIndex].value;

  // SORT SALARIES DESCENDING
  allData.sort(function(a, b) {
    return b.salary - a.salary;
  })

  //call `manipulateData` and pass `allData` to the param for filtering
  let filteredData = manipulateData(allData, selectedValue)

  // LIMIT TO ONLY 2 RECORDS
  filteredData = filteredData.filter((value, index) => {
    return (index < 2);
  });

  console.log(filteredData)
  // RENDER THE CHART
  //renderChart(filteredData);
}

function manipulateData(filteredData, selectedValue) {
  if(selectedValue === "All") {
    return filteredData;//skip this logic, if the value is `All`
  }

  return filteredData.filter(e => e.role === selectedValue)
}
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="description" content="">
        <title>Example</title>

    </head>
    <body>

    <div class="container-fluid">

        <!-- header -->
        <div class="row justify-content-center">
            <div class="align-self-center">
                <h1>Example</h1>
            </div>
        </div>

        <!-- drop down menu -->
        <div class="row justify-content-center">
            <div class="align-self-center">
                <div class="user-control">
                    <div class="form-group">
                        <select id="employee-role" class="form-control">
                            <option value="All">All Roles</option>
                            <option value="Sales">Sales</option>
                            <option value="Finance">Finance</option>
                        </select>
                    </div>
                </div>
            </div>
        </div>

<button onclick="filterData()">
Check filtered data
</button>

        <!-- container of bar chart -->
        <div id="chart-area"></div>

    </div>
    </body>
</html>

Note that I added Check filtered data for the demo purpose. You can remove it and fill in other elements at your needs.

You want to modify the results down to the top two earners after the data is filtered.

filteredByRole.slice(0, 2);

Details are commented in example

const employees = [{
  id: 1,
  name: 'John Smith',
  role: 'Sales',
  salary: 100000
}, {
  id: 2,
  name: 'Mary Jones',
  role: 'Finance',
  salary: 78000
}, {
  id: 3,
  name: 'Philip Lee',
  role: 'Finance',
  salary: 160000
}, {
  id: 4,
  name: 'Susan Williams',
  role: 'Sales',
  salary: 225000
}, {
  id: 5,
  name: 'Jason Alexander',
  role: 'Finance',
  salary: 90000
}, {
  id: 6,
  name: 'Derek Sanders',
  role: 'Sales',
  salary: 140000
}];

const data = employees.sort((a, b) => b.salary - a.salary);

// Declare empty array outside of function
let filteredByRole = [];

// Register the <select> to the "change" event
document.getElementById("employee-role").onchange = filterRole;

// Event handler passes event object by default
function filterRole(event) {
  // Assign the current value of <select> to a variable
  const role = this.value;
  /* 
  If <select> current value is "All" then the array is the same...
  ...otherwise, filter each object (employee) and return only the properties
  that has a value that matches the current value of <select>
  */
  if (role === "All") {
    filteredByRole = data.slice(0);
  } else {
    filteredByRole = data.filter(employee => employee.role === role);
  }
  // Log the filtered data
  console.log("Filtered by Role: ");
  console.log(JSON.stringify(filteredByRole));
  console.log("|||||||||||||||||||||||||||||");
  // Log the data for the top 2 earners
  console.log("Top two Earners by Role: ");
  console.log(JSON.stringify(filteredByRole.slice(0, 2)));
  console.log("|||||||||||||||||||||||||||||");
}
<select id="employee-role" class="form-control">
  <option value="All">All Roles</option>
  <option value="Sales">Sales</option>
  <option value="Finance">Finance</option>
</select>

Related