Сlientside callback. sessionStorage does't save

Hello

I cant understand how works window.sessionStorage(‘_dash_persistence.checklist.value.true’ )

my code

python file

import dash_bootstrap_components as dbc
from dash import Dash, html, dcc, Input, Output, State, callback_context, no_update, callback, clientside_callback, ClientsideFunction
from sql_execute import get_lpu, create_counter


app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP], update_title=None)

lpu_list = [{'label': f'lpu{lpu}', 'value': f'lpu{lpu}'} for lpu in range(10)]

# lpu_list = get_lpu()

lpu_allert = [{}]

allert = ["allert"]

app.layout = html.Div([
    html.Div(
        html.Div(
            [
                html.H6('medical organization', className='h6span'),
                html.Div(
                    id='view',
                    className='view'
                ),
                dbc.DropdownMenu(
                    id="dropdown-menu",
                    align_end=True,
                    color="secondary",
                    # label=[html.Img(src="/assets/dropdown-arrow-svgrepo-com.svg")],
                    children=[
                        html.Div(
                            id='select_all', className='noselect', children=html.Div(
                            children=[html.Img(src="/assets/bx-list-check.svg"),
                             html.Span("Выбрать все"),
                                ]
                            ),
                        ),
                        html.Div(
                            [
                                dcc.Input(
                                    id="search-input",
                                    type="text",
                                    placeholder="Type to filter",
                                    autoComplete="off",
                                    style={'marginleft': '.5rem'},
                                    className='search-input'
                                ),
                            ],
                            id="input-container",
                        ),
                        dbc.DropdownMenuItem(divider=True),
                        dcc.Checklist(
                            id = 'checklist',
                            options=lpu_list,
                            persistence_type='session',
                            persistence=True,
                            # inputClassName='form-check-input'
                        ),
                        html.Span(children='', id='empty_checklist')
                    ]
                ),
                html.Div(id='output_div', children=['put_me1']),
                html.Div(id='output_div1', children=['put_me2'])
            ],
            className='selector_border',
            style={
                'justifycontent': 'center'
            },
        ),
    ),
])


app.clientside_callback(
    ClientsideFunction(
        namespace='clientside',
        function_name='restore_checklist_value_onload'
    ),
    Output('output_div1', 'children'),
    Input('output_div','n_clicks'),
    State("checklist", "options"),
    prevent_initial_call=True
)

app.clientside_callback(
    ClientsideFunction(
        namespace='clientside',
        function_name='viev_session_storage'
    ),
    Output('output_div', 'children', allow_duplicate=True),
    Input('output_div1','n_clicks'),
    State("checklist", "options"),
    prevent_initial_call=True
)

# @app.callback(Output('checklist', 'value', allow_duplicate=True),
#               Input('output_div','n_clicks'),
#               State('checklist', 'value'),
#               prevent_initial_call=True)
# def testf(n_clicks, v1):
#     print(v1)
#     return no_update


app.clientside_callback(
    f'''
    function printValue(search_value) {{
        let lowerCaseSearchValue = search_value.toLowerCase();
        let lpu_list  = {lpu_list};
        
        console.log(lpu_list)

        let found = lpu_list.filter(element => element.value.toLowerCase().includes(lowerCaseSearchValue));

        if (found.length > 0) {{
            return found;
        }} else {{
            return {lpu_allert};
        }}
    }}
    ''',
    Output("checklist", "options"),
    Input("search-input", "value"),
    prevent_initial_call=True)


app.clientside_callback(
    ClientsideFunction(
        namespace='clientside',
        function_name='view_callback'
    ),
    Output('view', 'children'),
    Input('checklist', 'value')
)


app.clientside_callback(
    ClientsideFunction(
        namespace='clientside',
        function_name='select_all_value'
    ),
    Output('checklist', 'value'),
    Input('select_all', 'n_clicks'),
    State('checklist', 'options'),
    prevent_initial_call=True
)



if __name__ == '__main__':
    app.run(debug=True, dev_tools_ui=True)

js

window.dash_clientside = Object.assign({}, window.dash_clientside, {
    clientside: {
        view_callback: function(value) {

            if (typeof value === "undefined") {
                return []
            }
            else {
                let formattedString = value.join(', ')
                return formattedString;
            }
        },
        select_all_value: function (n_clicks, options, value) {

            const optionsArray = options.map(item => item.value);

            console.log(window.sessionStorage)

            window.sessionStorage.setItem('_dash_persistence.checklist.value.true', JSON.stringify([optionsArray]));

            console.log(window.sessionStorage)

            return optionsArray
        },
        viev_session_storage(n_clicks, options) {
            console.log(options)

            const optionsArray = options.map(item => item.value)

            window.sessionStorage.setItem('_dash_persistence.checklist.value.true', JSON.stringify([optionsArray]));

            return optionsArray;
        },
        restore_checklist_value_onload(n_clicks, options) {
            console.log(window.sessionStorage)
            return ['put_me2']
        }
    }
});

I’m trying to make a ‘select_all’ button.

First case :

The user opens the page for the first time. Than put the DropdownMenu and click at select all element. At this time it works clientside_callback select_all_value. JS get setItem in sessionStorage (you can see that in console). User update page and the stored values are not pulled up. I cant understand why value dosent save

anim1

Second case
When opening, the user will click on the “put_me2” button. Next, it will refresh the page and all the values will catch up. Although the callback code is identical
anim2

I will be very grateful if you point out my mistake to me

Thank you in advance for reading my post

I can’t figure out why window.sessionStorage.setItem(‘_dash_persistence.checklist.value.true’, JSON.stringify([optionsArray])) is being deleted

Hello @zaphire121,

Why are you trying to set the persistence manually?

I think the issue here is that you are passing options in the background, typically if you want the persistence to load what you set in the server.

You could look into something like this with selection as persistence.

Hi @jinnyzor . I need to implement the function of selecting all values.
I use “clientside_callback” to minimize the load on the server

You could look into something like this with selection as persistence.
I wont to use dcc.Checklist

My function works correctly, but after it processes, the value of session.Storage is erased

As a result, I want to get a button for selecting all values and saving their values in the user session

sessionStorage isn’t going to be a server call, it should be set inside if the props locally in the browser.

@jinnyzor sessionStorage works as it should.
I added this code to verify your statement

@app.callback(
    Output('output_div1', 'children'),
    Input('output_div','n_clicks'),
    State("checklist", "value"),
    prevent_initial_call=True
)
def ttt(n_clicks, value):
    print(value)

anim2

I can’t understand why if I do “Output(‘checklist’, ‘value’)” saving doesn’t work, but highlighting does. But if you change the “output”, saving works

Ah.

You can’t save from a callback, it has to be driven from a client interaction on the browser.

That is a current limitation.

@jinnyzor , How do I make the select all function work? :sweat_smile:

Like I suggested, you can use AG grid, the selectAll can trigger and should be able to store easily.

Is it impossible to configure this using ‘dcc.Checklist’?

I don’t think you can use select all in how you want to.

You are welcome to continue trying.

Thank you @jinnyzor for trying to help me. I think some JS script is being executed that clears the session

I know that when I’ve tried to do it, it won’t set.

I think it is an issue between React and JS.

Please tell me, what is the chance that this forum will be able to help me with such a special problem?

I have 2 ideas
first : using dcc Store
second : create new session storage with any key

But if the possibility of selecting all values works, then I will be very happy

Please, try running the example that I posted above.

Just add the persistence=True and session for your AG grid.

I can’t track why JS localStorage is instantly erased after work

window.dash_clientside = Object.assign({}, window.dash_clientside, {
    clientside: {
        view_callback: function(value) {
            if (typeof value === "undefined") {
                return []
            }
            else {
                let formattedString = value.join(', ')
                return formattedString;
            }
        },
        test_callback: function (n_clicks, options) {
            const optionsArray = options.map(item => item.value);
            window.localStorage.setItem('_dash_persistence.checklist.value.true', JSON.stringify([optionsArray]))
            return optionsArray
        },

    }
});

If you really have your heart set on this, you may be able to do this:

app.clientside_callback(
    ClientsideFunction(namespace='clientside', function_name='test_callback'),
    Output('_dash_persistence.checklist.value.true', 'data', allow_duplicate=True),
    Output('checklist', 'options'),
    Input(whateverinput)
)
view_callback: function(value) {
            if (typeof value === "undefined") {
                return []
            }
            else {
                let formattedString = value.join(', ')
                return formattedString;
            }
        },
        test_callback: function (n_clicks, options) {
            const optionsArray = options.map(item => item.value);
            return [optionsArray, optionsArray]
        }
``

It is not working :smiling_face_with_tear:

raise exceptions.InvalidComponentIdError(
dash.exceptions.InvalidComponentIdError: The element _dash_persistence.checklist.value.true contains . in its ID.
Characters ., { are not allowed in IDs.

I think we need to find out what is being done in JS when clicking on a value and do the same with all values. But I didn’t find anything. Apparently I’m not too competent

I am telling you, I have manipulated information directly via JS, and it does not sync with the React/Dash server. You cannot innately manipulate the persistence unless you do so via the application because of how React Properties work.

You have to use some other sort of means to sync it, but sync the issue is the callback, you wont be able to directly save it.

My #1 recommendation is using AG Grid, because the selectedRows are saved independently, and when you send it selectAll in a callback, the selectedRows are updated in the grid and then would be persisted.