Skip to content

Commit

Permalink
bug(data frame filter): When the filter is reset, be sure to use a ""…
Browse files Browse the repository at this point in the history
… value for the input (#1557)
  • Loading branch information
schloerke authored Jul 18, 2024
1 parent 76cee50 commit dc0b294
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Other changes

### Bug fixes

* Fixed bug where calling `.update_filter(None)` on a data frame renderer did not visually reset non-numeric column filters. (It did reset the column's filtering, just not the label). Now it resets filter's label. (#1557)

* Require shinyswatch >= 0.7.0 and updated examples accordingly. (#1558)

### Bug fixes
Expand Down
5 changes: 4 additions & 1 deletion js/data-frame/filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ export const Filter: FC<FilterProps> = ({ header, className, ...props }) => {
return (
<input
{...props}
value={header.column.getFilterValue() as string}
// If there was a value and now there isn't,
// set the filter value to `""` and not `undefined`.
// `undefined` will not clear the displayed value.
value={(header.column.getFilterValue() as string) || ""}
className={`form-control form-control-sm ${className}`}
type="text"
onChange={(e) => header.column.setFilterValue(e.target.value)}
Expand Down
8 changes: 4 additions & 4 deletions shiny/www/py-shiny/data-frame/data-frame.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions shiny/www/py-shiny/data-frame/data-frame.js.map

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions tests/playwright/shiny/components/data_frame/filter_reset/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from typing import cast

import pandas as pd
from palmerpenguins import load_penguins # pyright: ignore[reportMissingTypeStubs]

from shiny import reactive
from shiny.express import input, render, ui

penguins = cast(pd.DataFrame, load_penguins())

ui.input_action_button("update_filters", "Update filters")
ui.input_action_button("reset_filters", "Reset filters")

ui.h5("Current filters: ", {"class": "pt-2"})


@render.code
def penguins_code():
return str(penguins_df.filter())


@render.data_frame
def penguins_df():
return render.DataGrid(penguins, filters=True)


@reactive.effect
@reactive.event(input.update_filters)
async def _():
await penguins_df.update_filter(
[
{"col": 0, "value": "Gentoo"},
{"col": 2, "value": (50, None)},
{"col": 3, "value": (None, 17)},
{"col": 4, "value": (220, 225)},
],
)


@reactive.effect
@reactive.event(input.reset_filters)
async def _():
await penguins_df.update_filter(None) # <<
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from playwright.sync_api import Page, expect

from shiny.playwright import controller
from shiny.run import ShinyAppProc


def test_filters_are_reset(page: Page, local_app: ShinyAppProc) -> None:
page.goto(local_app.url)

penguin_df = controller.OutputDataFrame(page, "penguins_df")
penguin_code = controller.OutputCode(page, "penguins_code")
update_filters = controller.InputActionButton(page, "update_filters")
reset_filters = controller.InputActionButton(page, "reset_filters")

filter_inputs = penguin_df.loc_column_filter.locator("input")

expect(filter_inputs).to_have_count(8 + 5) # 8 columns including 5 numeric columns

penguin_code.expect_value("()")
for element in filter_inputs.element_handles():
assert element.input_value() == ""

update_filters.click()

penguin_code.expect_value(
"("
"{'col': 0, 'value': 'Gentoo'}, "
"{'col': 2, 'value': (50, None)}, "
"{'col': 3, 'value': (None, 17)}, "
"{'col': 4, 'value': (220, 225)}"
")"
)
for value, element in zip(
["Gentoo", "", "50", "", "", "17", "220", "225", "", "", "", "", ""],
filter_inputs.element_handles(),
):
assert element.input_value() == value

reset_filters.click()

penguin_code.expect_value("()")
for element in filter_inputs.element_handles():
assert element.input_value() == ""

0 comments on commit dc0b294

Please sign in to comment.