Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).

## [UNRELEASED]

## Added
- [#3669](https://github.com/plotly/dash/pull/3669) Selection for DataTable cleared with custom action settings

## Added
- [#3523](https://github.com/plotly/dash/pull/3523) Fall back to background callback function names if source cannot be found

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export default () => {
page_current,
page_size
]);
const selectedRowsCache = memoizeOneWithFlag(
selected_rows => selected_rows
);
const sortCache = memoizeOneWithFlag(sort => sort);
const viewportCache = memoizeOneWithFlag(viewport => viewport);
const viewportSelectedColumnsCache = memoizeOneWithFlag(
Expand All @@ -37,6 +40,7 @@ export default () => {
page_action,
page_current,
page_size,
selected_rows,
sort_action,
sort_by,
viewport,
Expand Down Expand Up @@ -64,17 +68,19 @@ export default () => {
const invalidatedFilter = filterCache(filter_query);
const invalidatedPagination = paginationCache(page_current, page_size);
const invalidatedSort = sortCache(sort_by);
const invalidatedSelectedRows = selectedRowsCache(selected_rows);

const invalidateSelection =
(!invalidatedFilter.cached &&
invalidatedSelectedRows.cached &&
((!invalidatedFilter.cached &&
!invalidatedFilter.first &&
filter_action.type === TableAction.Custom) ||
(!invalidatedPagination.cached &&
!invalidatedPagination.first &&
page_action === TableAction.Custom) ||
(!invalidatedSort.cached &&
!invalidatedSort.first &&
sort_action === TableAction.Custom);
(!invalidatedPagination.cached &&
!invalidatedPagination.first &&
page_action === TableAction.Custom) ||
(!invalidatedSort.cached &&
!invalidatedSort.first &&
sort_action === TableAction.Custom));

const newProps: Partial<SanitizedAndDerivedProps> = {};

Expand Down
107 changes: 107 additions & 0 deletions components/dash-table/tests/selenium/test_selected_rows_custom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import dash
from dash.dependencies import Input, Output
from dash import html
from dash.dash_table import DataTable

import json
import time
import pandas as pd

url = "https://github.com/plotly/datasets/raw/master/" "26k-consumer-complaints.csv"
rawDf = pd.read_csv(url, nrows=100)
rawDf["id"] = rawDf.index + 3000
df = rawDf.to_dict("records")


def get_app():
app = dash.Dash(__name__)

app.layout = html.Div(
[
DataTable(
id="table",
columns=[{"name": i, "id": i} for i in rawDf.columns],
data=df,
row_selectable="multi",
selected_rows=[],
filter_action="custom",
filter_query="",
sort_action="custom",
sort_by=[],
page_action="custom",
page_current=0,
page_size=10,
style_cell=dict(width=100, min_width=100, max_width=100),
),
html.Button("Set selected + sort_by", id="sort"),
html.Button("Set selected + filter", id="filter"),
html.Button("Set selected + page", id="page"),
html.Div(id="selected_rows_output"),
]
)

@app.callback(
Output("selected_rows_output", "children"),
Input("table", "selected_rows"),
)
def show_selected_rows(selected_rows):
return json.dumps(selected_rows) if selected_rows is not None else "None"

@app.callback(
Output("table", "selected_rows"),
Output("table", "sort_by"),
Input("sort", "n_clicks"),
prevent_initial_call=True,
)
def set_selected_and_sort(_):
return [0, 1, 2], [{"column_id": rawDf.columns[0], "direction": "asc"}]

@app.callback(
Output("table", "selected_rows", allow_duplicate=True),
Output("table", "filter_query"),
Input("filter", "n_clicks"),
prevent_initial_call=True,
)
def set_selected_and_filter(_):
return [0, 1, 2], "{} > 1".format(rawDf.columns[0])

@app.callback(
Output("table", "selected_rows", allow_duplicate=True),
Output("table", "page_current"),
Input("page", "n_clicks"),
prevent_initial_call=True,
)
def set_selected_and_page(_):
return [0, 1, 2], 1

return app


def test_tsrc001_selected_rows_persists_with_sort_by(test):
test.start_server(get_app())

test.find_element("#sort").click()
time.sleep(1)

assert test.find_element("#selected_rows_output").text == json.dumps([0, 1, 2])
assert test.get_log_errors() == []


def test_tsrc002_selected_rows_persists_with_filter_query(test):
test.start_server(get_app())

test.find_element("#filter").click()
time.sleep(1)

assert test.find_element("#selected_rows_output").text == json.dumps([0, 1, 2])
assert test.get_log_errors() == []


def test_tsrc003_selected_rows_persists_with_page_current(test):
test.start_server(get_app())

test.find_element("#page").click()
time.sleep(1)

assert test.find_element("#selected_rows_output").text == json.dumps([0, 1, 2])
assert test.get_log_errors() == []
Loading