dash-mantine-components icon indicating copy to clipboard operation
dash-mantine-components copied to clipboard

Implements Issue #173: Add n_submits property to TextInput

Open jacobswe opened this issue 2 years ago • 1 comments
trafficstars

This implements the issue I raised on the Discord and then in #173. Essentially, the goal is to be able to replicate the behavior of dcc.Input, specifically how it handles what it calls n_submit, which looking through their source code is essentially just incrementing a count of the number of times the enter key has been pressed.

I've gotten this working locally on my end. It seems like a pretty trivial change... but these are also the first lines of TypeScript that I've ever written, so feel free to let me know if there are any issues here. Really love the package and use it for everything, so I'm happy to have gotten a reason to dig a little deeper into how it all works.

MRE:

from dash import Dash, html, callback, Output, Input, State
import dash_mantine_components as dmc

app = Dash(__name__)

app.layout = html.Div([
    dmc.TextInput(id='text-input'),
    dmc.Text('Nothing yet submitted', id='text-output')
])

@callback(
    Output('text-output', 'children'),
    Input('text-input', 'n_submit'),
    State('text-input', 'value'),
    prevent_initial_call=True
)
def test_textinput_n_submit(n_submit, text_input):
    return text_input

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

jacobswe avatar Apr 12 '23 05:04 jacobswe

I started hitting roadblocks even with an n_submit approach to designing a chatbot in Dash, so I had to resort to using a dash-extensions EventListener and a clientside callback to parse the events. While way more complex that I wanted at the start, this solves the issues I was having. I still think it might be a good idea to implement a change like this, but wanted to share my solution in the meantime.

from dash import Dash, Input, Output, State, html, dcc
import dash_mantine_components as dmc
from dash_extensions import EventListener
from dash.exceptions import PreventUpdate

event = {"event": "keydown", "props": ["key", "shiftKey"]}

app = Dash()
app.layout = html.Div(
    [
        dcc.Store(id="message-data-placeholder"),
        EventListener(
            dmc.Textarea(placeholder="enter text", id="ta"), events=[event], id="el"
        ),
        dcc.Markdown("No text submitted", id="text-output"),
    ]
)

app.clientside_callback(
    """
    function(n_events, event, text) {
        if (event.key === "Enter" && !event.shiftKey) {
            return {
                "message":text
            };
        } else {
            return window.dash_clientside.no_update;
        }
    }
    """,
    Output("message-data-placeholder", "data"),
    Input("el", "n_events"),
    State("el", "event"),
    State("ta", "value"),
    prevent_initial_call=True,
)


@app.callback(
    Output("text-output", "children"),
    Output("ta", "value"),
    Input("message-data-placeholder", "data"),
    prevent_initial_call=True,
)
def handle_message_submit(message_data):
    return message_data["message"], ""


if __name__ == "__main__":
    app.run_server()

jacobswe avatar May 16 '23 14:05 jacobswe