Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

Unregistered dcc input components are having their contents cleared after callback updates #40

Closed
ned2 opened this issue Jan 11, 2018 · 14 comments · Fixed by #126
Closed
Labels
Status: Discussion Needed Type: Bug Something isn't working as intended

Comments

@ned2
Copy link

ned2 commented Jan 11, 2018

I haven't tested this thoroughly, but looks like it might be the case that when a dcc input component is included in a layout but is not registered with a callback, when any callback runs and the page is updated, the unregistered component's input contents are cleared. eg a dropdown that had a user selection made is reset to its initial value. If the component is then registered as a State of a callback whose value is is ignored, the initial value is then preserved as expected after a callback updates.

See this discussion: https://community.plot.ly/t/callbacks-clearing-all-unconnected-core-components-values/7631

While having unused components is probably an unlikely scenario in a completed app, it's certainly going to be confusing behaviour if someone has created a complete layout and is then going through implementing and testing callbacks incrementally -- as occurred in that discussion.

(hopefully I landed this in the right repo!)

@bpostlethwaite
Copy link
Member

Hi thanks for posting the issue and linking back to the community post. The script posted in the community forums is fairly lengthy. Are you able to post a minimal Dash script here that can reproduce the issue?

If you can make that happen we'll reproduce the issue on our end and take action. Thanks!

@ned2
Copy link
Author

ned2 commented Aug 19, 2018

Finally got around to making a minimal example that illustrates this buggy behaviour.

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, State, Output

app = dash.Dash()
app.layout = html.Div([
    html.Div(id='target'),
    dcc.Input(id='my-input', type='text', value=''),
    html.Br(),
    dcc.Input(id='my-input-missing', type='text', value=''),
    html.Br(),
    html.Button(id='submit', n_clicks=0, children='Save')
])

@app.callback(Output('target', 'children'), [Input('submit', 'n_clicks')],
              [State('my-input', 'value')])
def callback(n_clicks, state):
    return "callback received value: {}".format(state)

if __name__ == '__main__':
    app.run_server(debug=True)

The second Input component in the layout is not registered with a callback. If you enter text into both inputs then hit save, the second one's text will be cleared. Perhaps we should be catching this situation in layout validation since this is not a situation that a user probably meant to arrive at, with an unused component. However it would still be good to stop the clearing of the field anyway.

@ned2 ned2 added the Type: Bug Something isn't working as intended label Aug 19, 2018
@ned2 ned2 assigned ned2 and unassigned ned2 Sep 23, 2018
@ned2
Copy link
Author

ned2 commented Sep 23, 2018

Hey @bpostlethwaite, I've put together a minimal example that shows that this indeed a bug. What do you think the next steps here are?

@bpostlethwaite
Copy link
Member

We'll queue it for fixing! Thanks for posting the minimal example

@T4rk1n
Copy link
Contributor

T4rk1n commented Oct 29, 2018

It's the dcc.Input that doesn't have a check if the props is the same as the initial value before setting setState in componentWillReceiveProps. I added one and the bug was gone.

Due to how the dash-renderer render the layout, the components will receive the same initial props when updating the layout so they should check that they are not given the same initial props when using state and they don't have setProps.

@T4rk1n
Copy link
Contributor

T4rk1n commented Oct 30, 2018

@ned2 I fixed the Input in plotly/dash-core-components#350, I think that is something we'll have to watch out for when developing dash component as I don't think we can patch that in the renderer.

@ned2
Copy link
Author

ned2 commented Nov 3, 2018

Great! Ah, so it was specific to dcc.Input. We should update the relevant gotcha entry in the FAQs page then. Maybe just remove it entirely from that page, and then potentially also add something to the Component Development section, as it sounds like the gotcha now applies to component developers rather than users?

@ned2
Copy link
Author

ned2 commented Nov 3, 2018

Or is it worth leaving it in as a potential gotcha in the event that a component author hasn't handled this?

@T4rk1n
Copy link
Contributor

T4rk1n commented Nov 3, 2018

It's not specific to the input, the fix I had made was actually incomplete, the good pattern is the one @valentijnnieman did in plotly/dash-core-components#356

Only use the state if there's no setProps, don't derive state from the props or they might get the props from the initial layout.

I think it's because of the initial layout and hydration of the components in TreeContainer, they get the props back when a component update because the TreeContainer updates. I would leave this issue because it has some context and someone might be able to find a fix for that in the future.

@ned2
Copy link
Author

ned2 commented Nov 5, 2018 via email

@erolosty
Copy link

If you don't use an Input's value in any callback, it will be cleared.

It's a bug, but not terribly important, as if you don't care about that Input, Dash not caring either isn't the end of the world

Confused me for a while too

@Marc-Andre-Rivet
Copy link
Contributor

Marc-Andre-Rivet commented Mar 15, 2019

@ned2 With #126, the renderer's behavior has changed. setProps is now always present and it will always update the component props, whether it is used in a callback or not. If it is used in a callback, the props will be filtered and only the necessary props will be sent to Dash for processing. To be released in Dash 0.40.0.

While having unused components is probably an unlikely scenario in a completed app

Very late to the party, but I think it's worth pointing out that with the table, it is frequent for that component to be the last in a chain of callbacks and for no one but the end-user to be making changes to it (e.g. readonly w/ front-end driven filtering/sorting), resulting in an undefined setProps and weird behavior.

@ned2
Copy link
Author

ned2 commented Mar 15, 2019

That's amazing! I've been seeing this issue pop up a fair bit in the forums recently. Definitely great for a smoother Dash development experience.

Actually, I just tried out the example I posted a while back, and that buggy behaviour with the input seems to be already fixed in a previous release.

I might try to test it with a couple of other dcc types before closing the issue. I think I recall seeing this happening with dcc.Dropdown also.

@ned2
Copy link
Author

ned2 commented Mar 16, 2019

Just tested this with a missing Dropdown element, and its also not being cleared. Hooray!

Strangely, as mentioned, this is working on the current version of Dash, so a previous change seems to have improved the situation already. Regardless, I think we can close this now.

@ned2 ned2 closed this as completed Mar 16, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Status: Discussion Needed Type: Bug Something isn't working as intended
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants