plotly / dash-table

OBSOLETE: now part of https://github.com/plotly/dash
https://dash.plotly.com
MIT License
420 stars 74 forks source link

React "Max update depth exceeded" error with tooltips #883

Open cpascale43 opened 3 years ago

cpascale43 commented 3 years ago

Mark's app shows the below errors while using both tooltip_conditional and tooltip_data. The tooltips still render, but this breaks parts of his app including a script that tweaks the position and innerText of the DataTable's export button.

image002 (1)

This is a skeleton of his DataTable implementation:

# app.py
sensitivity_dict = {'Medium': 'Medium Sensitivity', 'High': 'High Sensitivity', 'Low': 'Low Sensitivity'}
tt_data = [{c: {'type': 'text', 'value': sensitivity_dict[d], 'delay': 100, 'duration': 3000} for c, d in row.items() if
            c == 'data sensitivity'} for row in df.to_dict('rows')]
tt_data = [
    {c: {'type': 'text', 'value': str(d), 'delay': 100, 'duration': 3500} for c, d in row.items() if c in df} for
    row in df.to_dict('rows')]
tt_cond = [
    {
        'if': {
            'filter_query': '{data sensitivity} = "Medium"',
            'column_id': 'data sensitivity'
        },
        'delay': 100,
        'value': 'Medium Sensitivity',
    },
    {
        'if': {
            'filter_query': '{data sensitivity} = "High"',
            'column_id': 'data sensitivity'
        },
        'delay': 100,
        'value': 'High Sensitivity',
    },
    {
        'if': {
            'filter_query': '{data sensitivity} = "Low"',
            'column_id': 'data sensitivity'
        },
        'delay': 100,
        'value': 'Low Sensitivity',
    },
]

app.layout = ddk.App([
    ddk.ControlCard(width=100, id='table-card', children=[
        ddk.DataTable(
            id='table',
            columns=[{"name": i, "id": i, 'hideable': True} for i in df],
            style_data_conditional=[
                {
                    'if': {'row_index': 'odd'},
                    'filter': 'brightness(120%)'
                }
            ],
            data=df.to_dict("rows"),
            # editable=True,
            fixed_rows={'headers': True},
            # page_size=50,
            style_table={
                'height': '67vh',
                'maxHeight': '67vh',
                'overflowY': 'auto'
            },
            style_filter={'height': '35px'},
            style_cell={
                'height': 'auto',
                # all three widths are needed
                'minWidth': '180px',
                'width': '180px',
                'maxWidth': '180px',
                #####
                'whiteSpace': 'pre-line',
            },
            style_as_list_view=True,
            filter_action="native",
            sort_action="native",
            sort_mode="multi",
            column_selectable="single",
            row_selectable="multi",
            row_deletable=True,
            selected_columns=[],
            selected_rows=[],
            page_action="native",
            export_columns='visible',
            export_format='csv',
            tooltip_data=tt_data,
            # tooltip_conditional=tt_cond,
        ),
        ddk.Row([
            html.Div(
                id="dl-csv-div",
                children=[
                    html.A(
                        [
                            html.Button(
                                "Download Full CSV",
                                id="full-csv-button",
                                style={'marginTop': '15px'},
                            )
                        ],
                        id="download-full-tbl",
                        download="full_data.csv",
                        href='',
                        target="_blank",
                    ),
                ]),
        ]),
    ])
])

# @app.callback(
#     Output('table', 'style_data_conditional'),
#     Input('data-sensitivity-colors', 'value')
# )

# @app.callback(
#     Output('table', 'data'),
#     [Input('forms-dropdown', 'value'),
#      Input('offices-dropdown', 'value'),
#      Input('systems-dropdown', 'value')]
# )

# @app.callback(
#     Output('forms-selected-card', 'value'),
#     Output('formats-selected-card', 'value'),
#     Output('systems-selected-card', 'value'),
#     Input('table', 'derived_virtual_row_ids')
# )
# tweaks.js
// function to create interval and remove once
function createInt(){
    var interval = setInterval(function(){
        // make sure Dash isn't still loading
        var loading = document.querySelector("._dash-loading-callback");
        if(tgt){
            tgt.style.overflow = "";
        }
        var tgt = document.querySelector(".sidebar--content");
        // if tgt exists and Dash isn't still loading, run command and remove interval
        if(tgt && !loading){
            tgt.style.overflow = "visible"
            if(tgt.style.overflow == "visible"){
                // document.removeEventListener("DOMContentLoaded", changeOverflow);
                clearInterval(interval);
            }
        }
    }, 1000)
}

function checkBtn(){
    var interval = setInterval(function(){
        var btn = document.querySelector('.export')
        var btn_div = document.getElementById('dl-csv-div');
        if(btn){
            btn_div.prepend(btn)
            btn.innerHTML = 'Download Filtered CSV';
            btn.style.marginRight = '10px';

            clearInterval(interval);
        }
    }, 100)
}

// Run the overflow function in an interval to be sure it runs properly
function changeOverflow(){
    createInt();
}

// listen for original content loading
document.addEventListener("DOMContentLoaded", function(){
    changeOverflow();
    checkBtn();
});

// listen for URL change
var oldHref = document.location.href;
window.onload = function(){
    var bodyList = document.querySelector("body");
    var observer = new MutationObserver(function(mutations){
        mutations.forEach(function(mutation){
            if(oldHref != document.location.href){
                oldHref = document.location.href;
                changeOverflow();
                checkBtn();
            }
        });
    });

    var config = {
        childList: true,
        subtree: true,
    }

    observer.observe(bodyList, config);
}

cc @plotly/product