Data Analyse Breda

React Table #5: Globale filters in een React Table

In deze serie posts vertellen we u meer over het gebruik van React Table. Deze bibliotheek stelt ons in staat om krachtige data tabellen te maken binnen React JS. We laten u zien hoe u een simpele tabel kan maken, hoe u vervolgens filters, sorteeropties, en pagination kan toevoegen, en hoe u de tabel kan stylen zodat het aantrekkelijk is voor gebruikers in uw applicatie.

In eerdere post hebben we al een basistabel gemaakt en een sorteerfunctie en kolomfilters toegevoegd. In deze post gaan we door met de code uit de voorgaande tutorials en gaan we aan de slag met het toevoegen van een globale filter. Aan het einde van deze post vindt u een werkend voorbeeld inclusief volledige code in onze Sandbox.

Globale filters

Een globale filter is een filter die de gebruikers in staat stelt om in alle kolommen tegelijk te filteren. Op deze pagina kan u daar meer over lezen. In deze blogpost laten we u zien hoe een globale filter kan inbouwen, en presenteren we u aan het eind een werkend voorbeeld in een sandbox.

Gebruik van globale filters

Om gebruik te kunnen gaan maken van globale filters dienen we een aantal aanpassingen te maken aan onze bestaande code. We gaan eerst de filter aanmaken in ons filters.js bestand. Daarna maken we wat aanpassingen aan ons Tabel.js bestand zodat de globale filter zichtbaar word boven onze tabel. Vervolgens laten we u zien hoe u bepaalde kolommen kan uitsluiten, zodat ze niet meegenomen worden in de zoekresultaten van de globale filter.

Aanmaken van de filters

In ons Filters.js bestand voegen we eerst de imports en de code van de filter toe. We beginnen met een import van useAsyncDebounce. Deze functie wordt gebruik om het aantal renders van de tabel in te perken. Onder de code van de filter leggen we uit wat deze functie precies doet.

Filters.js
import { useAsyncDebounce } from "react-table";

Nu gaan we onze globale filter toevoegen. Onder het blok vindt u de uitleg over deze code.

Filters.js

export const GlobaleFilter = ({
  globalFilter,
  preGlobalFilteredRows,
  setGlobalFilter
}) => {
  const count = preGlobalFilteredRows.length;
  const [value, setValue] = React.useState(globalFilter);
  const onChange = useAsyncDebounce((value) => {
    setGlobalFilter(value || undefined);
  }, 200);
  return (
    <input

      className="globalefilter"
      value={value || ""}
      onChange={(e) => {
        setValue(e.target.value);
        onChange(e.target.value);
      }}
      placeholder={`${count} rijen...`}
    />
  );
};
  • Binnen de constante GlobaleFilter vermelden we drie eigenschappen. Allereerst preGlobalFilteredRows, deze variable telt de rijen die over zijn na het filteren van de tabel. Daarnaast globalFilter, dat is de waarde die in de filter staat. Ten slotte setGlobalFilter, dit is de variable die de waarde van de globalFilter veranderd wanneer de gebruiker een verandering aanbrengt in de filter.
  • Binnen de constante GlobaleFilter bevinden zicht drie constantes die we gaan gebruiken in onze filter. Count telt het aantal rijen in de tabel met behulp van de preGlobalFilteredRows. De constanten value/ setvalue hebben hebben de waarde van de globalFilter. Wanneer er een verandering plaatsvindt in de filter wordt de onChange geactiveerd. Deze functie veranderd de waarde van de globale filter naar de waarde die de gebruiker ingevoerd heeft (setGlobalFilter).
  • De onChange functie is omringt door een useAsyncDebouce functie, deze functie zorgt ervoor dat de onChange functie niet oneindig draait, maar elke 200 milliseconden. De filter wordt nu dus niet geactiveerd bij elke letter die ingetypt word, maar vernieuwd elke 0.2 seconde de input van de gebruiker. Dit verbeterd de prestatie van de applicatie in de browser. Als we normaal gesproken cbi willen zoeken zou de filter bij elke nieuwe rerender vernieuwen, in dit geval bij de c, cb, en cbi. Door een kleine vertraging in te bouwen worden er minder venieuwingen gecommuniceerd en verbeterd de prestatie. Je kan zelf een aanpassing maken aan de milliseconden pauze die minimaal tussen de renders moeten zitten.
  • In de return statement hebben we een inputveld die de waarde van de gebruiker doorgeeft aan de value constante. Deze waarde wordt vervolgens doorgegeven aan de filter. De placeholder laat zien hoeveel rijen er beschikbaar zijn binnen de tabel.


Aanpassingen in het Tabel.js bestand

We gaan nu een aantal aanpassingen maken in het Tabel.js bestand die ervoor gaan zorgen dat de filter zichtbaar word boven onze tabel. Allereerst importeren we bovenaan ons bestand de GlobaleFilter. Daarnaast voegen we de useGlobalFilter hook toe aan de huidige imports van react table. Deze hebben we nodig om onze globale filter te laten werken.

Tabel.js 

import { GlobaleFilter } from "./Filters";
import { useTable, useSortBy, useFilters, useGlobalFilter } from "react-table";

Nu gaan we een verandering aanbrengen in onze useTable hook uit ons Tabel.js bestand. De dikgedrukte stukken zijn nieuwe ten opzichte van de voorgaande tutorial.

Tabel.js 

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    state,
    prepareRow,
    preGlobalFilteredRows,
    setGlobalFilter

  } = useTable(
    { columns, data, defaultColumn: { Filter: TekstFilter } },
    useFilters,
    useGlobalFilter,
    useSortBy
  );

Nu gaan we de filter boven de tabel plaatsen Dikgedrukt de nieuwe code met de globale filter.

Tabel.js 

return (
    <div>
      <GlobaleFilter
        preGlobalFilteredRows={preGlobalFilteredRows}
        globalFilter={state.globalFilter}
        setGlobalFilter={setGlobalFilter}
      />

      <table {...getTableProps()} className="tabel">
        <thead>
          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th {...column.getHeaderProps(column.getSortByToggleProps())}>
                  {column.render("Header")}
                  <span>
                    {column.isSorted
                      ? column.isSortedDesc
                        ? " 🔽"
                        : " 🔼"
                      : ""}
                  </span>
                </th>
              ))}
            </tr>
          ))}

          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th {...column.getHeaderProps()}>
                  <div>{column.canFilter ? column.render("Filter") : null}</div>
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row, i) => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map((cell) => {
                  return (
                    <td {...cell.getCellProps()}>{cell.render("Cell")}</td>
                  );
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );

Plaats de zoekbalk in de tabel

Je kan de filter ook onder je kolom filters plaatsen binnen de tabel. Hiervoor dienen we eerst een kleine toevoeging te maken aan onze useTable hook. We voegen visibleColumns toe zodat we weten hoeveel kolommen er zijn. Zo kunnen we later aangeven dat de table header van de zoekbalk even wijdt moet zijn als het totale aantal kolommen.

Tabel.js  
 const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    state,
    prepareRow,
    preGlobalFilteredRows,
    visibleColumns,
    setGlobalFilter
  } = useTable(
    { columns, data, defaultColumn: { Filter: TekstFilter } },
    useFilters,
    useGlobalFilter,
    useSortBy
  );


In de tabel plakken we nu de dikgedrukte code waarin we de filter in een table row en table header plaatsen. Hierin zie je duidelijk dat de colspan gelijk is aan het aantal zichtbare kolommen.

return (
    <div>

      <table {...getTableProps()} className="tabel">
        <thead>
          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th {...column.getHeaderProps(column.getSortByToggleProps())}>
                  {column.render("Header")}
                  <span>
                    {column.isSorted
                      ? column.isSortedDesc
                        ? " 🔽"
                        : " 🔼"
                      : ""}
                  </span>
                </th>
              ))}
            </tr>
          ))}

          {headerGroups.map((headerGroup) => (
            <tr {...headerGroup.getHeaderGroupProps()}>
              {headerGroup.headers.map((column) => (
                <th {...column.getHeaderProps()}>
                  <div>{column.canFilter ? column.render("Filter") : null}</div>
                </th>
              ))}
            </tr>
          ))}

          <tr>
            <th
              colSpan={visibleColumns.length}
              style={{
                textAlign: "left"
              }}
            >
              <GlobaleFilter
                preGlobalFilteredRows={preGlobalFilteredRows}
                globalFilter={state.globalFilter}
                setGlobalFilter={setGlobalFilter}
              />
            </th>
          </tr>
        </thead>
        <tbody {...getTableBodyProps()}>
          {rows.map((row, i) => {
            prepareRow(row);
            return (
              <tr {...row.getRowProps()}>
                {row.cells.map((cell) => {
                  return (
                    <td {...cell.getCellProps()}>{cell.render("Cell")}</td>
                  );
                })}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

Het uitsluiten van kolommen

Het kan voorkomen dat we niet alle kolommen willen meenemen in de globale filter. We kunnen kolommen uitsluiten in de columns constante binnen ons Tabel.js bestand. De onderstaande code laat zien hoe we de capaciteit kunnen uitsluiten in de globale filter. Wanneer u deze variabele gebruikt zal het opvallen dat ook de kolomfilter wegvalt wanneer u begint met typen in de globale filter. Als de globale filter leeg is zal de kolomfilter gewoon zichtbaar zijn.

Tabel.js 

  const columns = useMemo(
    () => [
      {
        Header: "Id",
        accessor: "id",
        Filter: MinMaxFilter,
        filter: "between"
      },
      {
        Header: "Clubnaam",
        accessor: "naam"
      },
      {
        Header: "Land",
        accessor: "land",
        Filter: DropdownFilter,
        filter: "equals"
      },
      {
        Header: "Stadion",
        accessor: "stadion"
      },
      {
        Header: "Capaciteit",
        accessor: "capaciteit",
        Filter: MinMaxFilter,
        filter: "between",
        disableGlobalFilter: true
      }
    ],
    []
  );


Resultaat en volledige code

In de sandbox hieronder vindt u het resultaat inclusief de volledige code. Het zal u opvallen dat de tabel er nog erg lelijk uit ziet en niet responsief is. Dit gaan we veranderen in de volgende tutorials. Ook gaan we aan de slag met pagination.

Leave a Reply