[BUG] dcc.Patch() wipes persistence of sibling pattern-matching elements
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 24.4k
- Forks
- 2.3k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 13
Description
Sibling of: https://github.com/plotly/dash/issues/3681
Environment
dash 4.4.0
When patching a new element to list of elements with pattern matched ids, persistence is wiped from all sibling IDs.
Minimal example:
from dash import ALL, Dash, Input, Output, Patch, dcc, html, clientside_callback, callback
app = Dash(__name__)
def make_input(index):
return dcc.Input(
id={"type": "inp", "index": index},
value="initial",
persistence=True,
persistence_type="local",
)
app.layout = html.Div(
[
html.Button("add", id="add"),
html.Button("clear", id="clear"),
html.Div([make_input(0), make_input(1)], id="container"),
html.Div(id="display"),
html.Pre(id="storage"),
dcc.Interval(id="local_storage_poll", interval=250),
dcc.Input("Hello, I don't wipe", id='non-pattern-matching-id', persistence=True, persistence_type='local')
]
)
@callback(
Output("container", "children"),
Input("add", "n_clicks"),
prevent_initial_call=True,
)
def add_input(n):
patch = Patch()
patch.append(make_input(n + 1))
return patch
@callback(Output("display", "children"), Input({"type": "inp", "index": ALL}, "value"))
def show(values):
return "|".join(values)
# Debug info, show local storage to make it easier to noticed when it's wiped
clientside_callback(
"""
function display_persisted_vals() {
return Object.keys(window.localStorage)
.filter(k => k.startsWith('_dash_persistence.'))
.map(k => k + ' = ' + window.localStorage.getItem(k))
.join('\\n') || '(nothing persisted)';
}
""",
Output("storage", "children"),
Input("local_storage_poll", "n_intervals"),
)
# Debug helper, clear local storage to do a clean test
# (helpful after the fix when the storage doesn't wipe constantly, lol)
clientside_callback(
"""
function clear_persistence() {
Object.keys(window.localStorage)
.filter(k => k.startsWith('_dash_persistence.'))
.forEach(k => window.localStorage.removeItem(k));
window.location.reload();
return window.dash_clientside.no_update;
}
""",
Output("clear", "n_clicks"),
Input("clear", "n_clicks"),
prevent_initial_call=True,
)
if __name__ == "__main__":
app.run(debug=True)
Here is a run of the minimal example app
Persistence works without a patch.
When a patch is applied persistence is wiped from siblings, but not from unrelated elements.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the minimal Dash application in the issue with Dash 4.4.0, then trace how dcc.Patch() updates children with pattern-matching IDs and how persistence is restored. Done means appending a new sibling preserves local persistence for existing pattern-matched inputs while unrelated persistence remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100