Accessing dash element Props on client side

Is there a way to have javascript/css access the properties of dash elements on the client side?

My use case is that I would like to style some elements based on the number of times they were clicked using client side code (i.e. avoiding firing a callback)

I could tie my own click event and keep a counter, but since these are Dash elements and Dash is already doing that (dash-html-components , and that I’m actually relying on n_clicks inside some other callbacks, I figured it would be better to use the n_clicks property from dash/react.

I found a way to get the data as follow:

d = document.getElementById('myElementId')
d.__reactInternalInstance$uxbml8qv1w._currentElement.props.n_clicks

However that seems a bit hackish to have to access the internal state in that fashion, not to mention needing to figure out the $xxxx id everytime.

Is there a more elegant/robust way to do that?

Thanks,

running into this issue again. Any chance someone could help?

In particular, I am writing some JS that I’d like to read properties from some plots as well as the dcc.Store object.

Thanks,

Hi zoohair,

Did you ever find a better solution?

And how did you go about getting the $XXXXX value?

Hi @HSpiegel

Why do you need to modify the css style without using a callback?

Did you ever get a solution on this one?

I ended up writing a function which returns the attribute that I care about. For example, in the code below I wanted to get access to the setProps function to trigger a callback manually.

[RegionSelectorSetter , _unused ] = findAttribute(document.getElementById('RegionSelector'), 'setProps')
RegionSelectorSetter({value: data['region']})

In my original question I’d have found the n_clicks property with something like:

 findAttribute(document.getElementById('myElementId'), 'n_clicks')
//Adapted from:
//https://stackoverflow.com/questions/40603913/search-recursively-for-value-in-object-by-property-name
function findAttribute(object, key) {
    var value;
    var path;
    Object.keys(object).some(function(k) {
        if (k === key) {
            value = object[k];
            path = k + '.' + path
            return true;
        }
        if (k.indexOf('__reactInternalInstance') == -1 //_reacInternal is annoyingly recursive?
            && object[k] 
            && typeof object[k] === 'object' 
            && object.hasOwnProperty(k)) {
            [value, path] = findAttribute(object[k], key);
            if(value !== undefined) {path = k + '.' + path}
            return value !== undefined;
        }
    });

    return [value, path];
}

The more Dash-y way to do this would be to use a clientside callback with a dummy output.

For instance with the button changing color based on the number of clicks:

In Python

clientside_callback(
    ClientsideFunction(namespace="clientside", function_name="styleButtonClicks"),
    output=Output("button_id", "data-dummy"),
    inputs=[Input("button_id", "n_clicks"), State("button_id", "id")]
)

And in assets/scripts.js

if (!window.dash_clientside) {
    window.dash_clientside = {};
}

window.dash_clientside.clientside = {
    styleButtonClicks: function(n_clicks, id) {
        var button = document.getElementById(id)
        if (n_clicks <= 1) {
            button.style.background = "green"
        } else if (n_clicks <= 3) {
            button.style.background = "yellow"
        } else (n_clicks <= 3) {
            button.style.background = "red"
        }
    }
}

Note: I did it with a dummy output in the example to show that you can do it but in this case you could update the style attribute of the button in the clientside callback.

3 Likes

Dash added clientside callbacks in 2019 (clientside callback interface by chriddyp · Pull Request #672 · plotly/dash · GitHub) which makes this much cleaner than my hack back in 2018 :stuck_out_tongue:

Thanks for providing an example @RenaudLN

1 Like

@zoohair does your initial suggestion to get the setProps function still work? Should I be able to use this on an input field too?