Filter DataTable By Column Value With Custom Dropdown Menu

In addition default search box in DataTables sometimes it’s nice to have the ability to filter by a specific DataTable column. This example shows how to use a custom drop-down menu to filter a DataTable by column value. I’m going to create a drop-down menu that displays the unique list of strings from a column called Category and when the user selects a category from the dropdown-menu, the datatable will be rendered with only records with the Category from the selected value.

Filter DataTable Example

View full working example.
Download full repo.

HTML

There are two main parts to the HTML, the category filter drop-down menu and the datatable. The values in the category filter will be the values that are to be filtered from the table when the user selects an item.

    <!-- Create the dropdown filter -->

   <div class="category-filter">
      <select id="categoryFilter" class="form-control">
        <option value="">Show All</option>
        <option value="Classical">Classical</option>
        <option value="Hip Hop">Hip Hop</option>
        <option value="Jazz">Jazz</option>
      </select>
    </div>

    <!-- Set up the datatable -->
    <table class="table" id="filterTable">
      <thead>
        <tr>
          <th scope="col">Artist</th>
          <th scope="col">Category</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td scope="col">Public Enemy</td>
          <td scope="col">Hip Hop</td>
        </tr>
        <tr>
          <td scope="col">Chet Baker</td>
          <td scope="col">Jazz</td>
        </tr>
        <tr>
          <td scope="col">Billie Holiday</td>
          <td scope="col">Jazz</td>
        </tr>
        <tr>
          <td scope="col">Vivaldi</td>
          <td scope="col">Classical</td>
        </tr>
        <tr>
          <td scope="col">Jurrasic 5</td>
          <td scope="col">Hip Hop</td>
        </tr>
        <tr>
          <td scope="col">Onyx</td>
          <td scope="col">Hip Hop</td>
        </tr>
        <tr>
          <td scope="col">Tchaikovsky</td>
          <td scope="col">Classical</td>
        </tr>
        <tr>
          <td scope="col">Oscar Peterson</td>
          <td scope="col">Jazz</td>
        </tr>
      </tbody>
    </table>

JavaScript

The JavaScript part relies on jQuery but can be modified to use vanilla javascript if you don’t have jQuery as part of the project. The code is commented below to give you an idea of what’s happening.

<script>
    $("document").ready(function () {

      $("#filterTable").dataTable({
        "searching": true
      });

      //Get a reference to the new datatable
      var table = $('#filterTable').DataTable();

      //Take the category filter drop down and append it to the datatables_filter div. 
      //You can use this same idea to move the filter anywhere withing the datatable that you want.
      $("#filterTable_filter.dataTables_filter").append($("#categoryFilter"));
      
      //Get the column index for the Category column to be used in the method below ($.fn.dataTable.ext.search.push)
      //This tells datatables what column to filter on when a user selects a value from the dropdown.
      //It's important that the text used here (Category) is the same for used in the header of the column to filter
      var categoryIndex = 0;
      $("#filterTable th").each(function (i) {
        if ($($(this)).html() == "Category") {
          categoryIndex = i; return false;
        }
      });

      //Use the built in datatables API to filter the existing rows by the Category column
      $.fn.dataTable.ext.search.push(
        function (settings, data, dataIndex) {
          var selectedItem = $('#categoryFilter').val()
          var category = data[categoryIndex];
          if (selectedItem === "" || category.includes(selectedItem)) {
            return true;
          }
          return false;
        }
      );

      //Set the change event for the Category Filter dropdown to redraw the datatable each time
      //a user selects a new filter.
      $("#categoryFilter").change(function (e) {
        table.draw();
      });

      table.draw();
    });
</script>

Full HTML/JS/CSS

Here is the full HTML with Javascript and a bit of CSS included.

<!doctype html>

<html lang="en">

<head>
  <meta charset="utf-8">

  <title>Add select drop-down filter to DataTable</title>
  <meta name="description" content="">
  <link rel="stylesheet" href="https://cdn.datatables.net/1.10.23/css/jquery.dataTables.min.css" />
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" />
<style>
  select.form-control{
    display: inline;
    width: 200px;
    margin-left: 25px;
  }
</style>
</head>

<body>
  <div class="container mt-4">
    <!-- Create the drop down filter -->
    <div class="category-filter">
      <select id="categoryFilter" class="form-control">
        <option value="">Show All</option>
        <option value="Classical">Classical</option>
        <option value="Hip Hop">Hip Hop</option>
        <option value="Jazz">Jazz</option>
      </select>
    </div>

    <!-- Set up the datatable -->
    <table class="table" id="filterTable">
      <thead>
        <tr>
          <th scope="col">Artist</th>
          <th scope="col">Category</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td scope="col">Public Enemy</td>
          <td scope="col">Hip Hop</td>
        </tr>
        <tr>
          <td scope="col">Chet Baker</td>
          <td scope="col">Jazz</td>
        </tr>
        <tr>
          <td scope="col">Billie Holiday</td>
          <td scope="col">Jazz</td>
        </tr>
        <tr>
          <td scope="col">Vivaldi</td>
          <td scope="col">Classical</td>
        </tr>
        <tr>
          <td scope="col">Jurrasic 5</td>
          <td scope="col">Hip Hop</td>
        </tr>
        <tr>
          <td scope="col">Onyx</td>
          <td scope="col">Hip Hop</td>
        </tr>
        <tr>
          <td scope="col">Tchaikovsky</td>
          <td scope="col">Classical</td>
        </tr>
        <tr>
          <td scope="col">Oscar Peterson</td>
          <td scope="col">Jazz</td>
        </tr>
      </tbody>
    </table>

  </div>

  <script src="https://code.jquery.com/jquery-3.5.1.min.js"
    integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

  <script src="https://cdn.datatables.net/1.10.23/js/jquery.dataTables.min.js"></script>

  <script>
    $("document").ready(function () {

      $("#filterTable").dataTable({
        "searching": true
      });

      //Get a reference to the new datatable
      var table = $('#filterTable').DataTable();

      //Take the category filter drop down and append it to the datatables_filter div. 
      //You can use this same idea to move the filter anywhere withing the datatable that you want.
      $("#filterTable_filter.dataTables_filter").append($("#categoryFilter"));
      
      //Get the column index for the Category column to be used in the method below ($.fn.dataTable.ext.search.push)
      //This tells datatables what column to filter on when a user selects a value from the dropdown.
      //It's important that the text used here (Category) is the same for used in the header of the column to filter
      var categoryIndex = 0;
      $("#filterTable th").each(function (i) {
        if ($($(this)).html() == "Category") {
          categoryIndex = i; return false;
        }
      });

      //Use the built in datatables API to filter the existing rows by the Category column
      $.fn.dataTable.ext.search.push(
        function (settings, data, dataIndex) {
          var selectedItem = $('#categoryFilter').val()
          var category = data[categoryIndex];
          if (selectedItem === "" || category.includes(selectedItem)) {
            return true;
          }
          return false;
        }
      );

      //Set the change event for the Category Filter dropdown to redraw the datatable each time
      //a user selects a new filter.
      $("#categoryFilter").change(function (e) {
        table.draw();
      });

      table.draw();
    });
  </script>
</body>

</html>

View full working example.
Download full repo.

Create multiple .env files in a React app

Configuring multiple environment files for a React app is handy if you have different variables for each environment (local, dev, test and production) – API endpoints is a good example. Like the name suggests, a .env file allows you to create environment specific variables that you specify to be used in specific builds for each of your environments. My projects usually have the four different environments:

  1. Local – My local machine where I do all my development.
  2. Development – This is the server environment where we can try new code outside our development machines. This is a server environment that is configured similar to test and production but is reserved to break things. Generally this environment is filled with dummy data and can become a mess pretty easily as we test out new features and debug code.
  3. Test or staging – A copy of the production environment where end users, testers and other folks from the team do their testing. This environment usually has the same data (minus any PII/PHI data) that production has.
  4. Production – This is the live site. You know what this is.

With these four environments I have five environment files in my React app structure. Each with their own variables that relate to the specific environment.

  • .env
    • This is a placeholder file that only shows the structure the other environment files should follow. For example:
      • REACT_APP_API_HOST=API_HOST
        REACT_APP_WEB_HOST=WEB_HOST
        REACT_APP_BUILD=BUILD
  • .env.development.local
    • This is the file that I use for my local development. I have this file added to .gitignore so it’s not checked into source control. Every developer should create this file locally and configure it with their local information.
  • .env.development
    • Development server
  • .env.staging
    • Staging server
  • .env.production
    • Production server

Then by utilizing the env-cmd package I’m able to run a command like npm run build:production to create my production build which uses the variables defined in the .env.production file. Same goes for local, development and testing/staging.

How to configure multiple .env files

Here’s how to set up a React application to utilize multiple .env files and variables. This example uses Create-React-App, so YMMV depending on what you bootstrapped your React app with.

1. Start off by creating a .env file at the root of your project for each of your environments.

Multiple .env files in React

2. Install the env-cmd package into your project npm install env-cmd

3. Open your package.json file and inside the scripts node add a line for each environment you will be building. You should already have lines for start, build, test and eject. Each line is specific to the build and .env file. So, build:development is the command you’ll run to create your development build, build: staging for testing and build:production for production.

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "build:development": "env-cmd -f .env.development react-scripts build",
    "build:staging": "env-cmd -f .env.staging react-scripts build",
    "build:production": "env-cmd -f .env.production react-scripts build"
  }

4. Add the environment specific variables to your environment files.

REACT_APP_API_HOST=https://localhost:5001
REACT_APP_WEB_HOST=http:localhost:3000
REACT_APP_BUILD=Development.Local

5. Run your build to create a build with your environment variables npm run build:production

Now you should have the ability to build your React apps with environment specific variables. Hopefully this makes your deployments easier and more straightforward.