plotly/dash-renderer

Dash-renderer will not render wildcard attributes

rmarren1 opened this issue · 3 comments

I added in plotly/dash-html-components#40 a wildcard attribute to handle the HTML data-* attributes.

This works fine for adding a data-* attribute to an object, and within callbacks you can update this value and use it to correctly to update other callbacks.

However, this attribute is not injected into the HTML on the client side, and it cannot be used to interact with javascript and css on the client side?

Any idea where to start for fixing this issue? I am guessing that there is a subset of properties that are actually rendered in HTML on the client side, and I could add wildcard attributes there. I am having trouble finding the piece of code that does this.

Hm, at first glance I'm actually not quite sure. dash-renderer shouldn't interfere with which properties can be rendered, that should be up to the component. And inside, the component, we're just passing all of the props through:
https://github.com/plotly/dash-html-components/blob/0d65ea60acdd9ee988e89a7b0e70d125edf53c89/src/components/Div.react.js#L20

I'll pull down the branches and take a look

image

Looking at the React tree (I use the react devtools: https://github.com/facebook/react-devtools), it looks like the data-* props aren't supplied to the tree.

Looking into the network request (/_dash-layout serves the app.layout to the front-end), it looks like the data-* prop wasn't serialized:
image

So, I suspect the issue has to do with serializing the component. Indeed, using the JSON serializer:

In [3]: import dash_html_components as html
   ...: import json
   ...: from plotly.utils import PlotlyJSONEncoder
   ...:
   ...: c = html.Div(
   ...:     id="my-id",
   ...:     children='data-*',
   ...:     **{
   ...:         'data-foo': 'foo',
   ...:         'data-bar': 'bar'
   ...:     }
   ...: )
   ...:
   ...: print(json.dumps(c, cls=PlotlyJSONEncoder, indent=2))
   ...:
{
  "type": "Div",
  "namespace": "dash_html_components",
  "props": {
    "children": "data-*",
    "id": "my-id"
  }
}

This serialization happens here: https://github.com/plotly/dash/blob/ff93d2c4331a576b445be87bb3b77576f18b030a/dash/dash.py#L159-L167

The cls=PlotlyJSONEncoder is here: https://github.com/plotly/plotly.py/blob/master/plotly/utils.py#L105, but the main thing to know is that the encoder looks for a .to_plotly_json method. This is supplied in Dash here: https://github.com/plotly/dash/blob/ff93d2c4331a576b445be87bb3b77576f18b030a/dash/development/base_component.py#L36-L45. It's likely that this needs to be updated

Changed https://github.com/plotly/dash/blob/ff93d2c4331a576b445be87bb3b77576f18b030a/dash/development/base_component.py#L36-L45
to

    def to_plotly_json(self):
        # Add normal properties
        props = {
            p: getattr(self, p)
            for p in self._prop_names  # pylint: disable=no-member
            if hasattr(self, p)
        }
        # Add the wildcard properties data-* and aria-*
        props.update({
            k: getattr(self, k)
            for k in self.__dict__
            if any(k.startswith(w) for w in
                   self._valid_wildcard_attributes)  # pylint:disable=no-member
        })
        as_json = {
            'props': props,
            'type': self._type,  # pylint: disable=no-member
            'namespace': self._namespace  # pylint: disable=no-member
        }


        return as_json

to fix.