Reflex Logo

Intro

Gallery

Hosting

Learn

Components

API Reference

Onboarding

Recipes

/

Filtered-table

This recipe uses an rx.foreach for the row generation with a computed var filtering the data for rows, using an input value for filter value.

Additionally, the filter input uses a debounce that limits the update, which prevents filtered data to be calculated on every keypress.

import reflex as rx
from typing import List, Dict

RAW_DATA = [
    {"name": "Alice", "tags": "tag1"},
    {"name": "Bob", "tags": "tag2"},
    {"name": "Charlie", "tags": "tag1"},
]
RAW_DATA_COLUMNS = ["Name", "tags"]


class FilteredTableState(rx.State):
    filter_expr: str = ""
    data: Dict[str, Dict[str, str]] = RAW_DATA

    @rx.cached_var
    def filtered_data(self) -> List[Dict[str, str]]:
        # Use this generated filtered data view in the `rx.foreach` of
        #  the table renderer of rows
        # It is dependent on `filter_expr`
        # This `filter_expr` is set by an rx.input
        return [
            row
            for row in self.data
            if self.filter_expr == ""
            or self.filter_expr != ""
            and self.filter_expr == row["tags"]
        ]

    def input_filter_on_change(self, value):
        self.filter_expr = value
        # for DEBUGGING
        yield rx.console_log(f"Filter set to: {self.filter_expr}")


def render_rows():
    return [
        rx.foreach(
            # use data filtered by `filter_expr` as update by rx.input
            FilteredTableState.filtered_data,
            render_row,
        )
    ]


def render_row(row):
    return rx.table.row(rx.table.cell(row["name"]), rx.table.cell(row["tags"]))


def render_table():
    return rx.container(
        rx.table.root(
            rx.table.header(
                rx.table.row(
                    *[rx.table.column_header_cell(column) for column in RAW_DATA_COLUMNS]
                )
            ),
            rx.table.body(
                *render_rows()
            )
        )
    )


def index() -> rx.Component:
    return rx.box(
        rx.box(
            rx.heading(
                "Filter by tags:",
            ),
            rx.input(
                on_change=FilteredTableState.input_filter_on_change,
                value=FilteredTableState.filter_expr,
                debounce_timeout=1000,
            ),
        ),
        rx.box(
            render_table(),
        ),
    )



app = rx.App()
app.add_page(index, route="/")

Did you find this useful?

HomeGalleryChangelogIntroductionHosting