How to view multi layout page in 1 screen

Hi all
I have a Dashboard like this. It is a multiple dash app that will include many pages: kpi1, kpi2, kpi3…
When we click on the corresponding navlink of any kpi, it will display the layout of that kpi,


But I want to see and compare between many different kpi, I want to display combine multiple layouts at once, is there any way to do that?

Hi,

Sorry I misread the question earlier.

So if I understand correctly you want to mix and match whatever KPI is selected at any given point? And the data and layout might be completely different?

You could for example structure it as a multipage-app, but all the similar, logic/presentation will be done in one page (you might have different pages for different views to keep it clean).

for your case you could use a sidebar with all the KPI’s and a checkbox next to them, as to be able to toggle the indicator.
The state will be maintained in a store and each kpi will have it’s layout attached which can be rendered on that page.

Another approach might be (if the data is rather similar), that you could use a comparison card type of system. with an add button next to each kpi. this will render whichever info you want, and the you could have on your actual content page "a remove action for the specific kpi section (or any other action you would like).

This is an example of a personal project I am working on which illustrates option 2.

It’s a multipage app, but all the logic/ for it to happen is on 1 page. the store containing the data is global in the app.

As you see the data is rather similar, but you could make it work for other types of data if you structure the layout correctly

1 Like

Can you share with me a bit about the structure source code?
Thank you so much

Hello @phuonghao145,

For this, I actually wouldn’t use pages in the nature that is currently designed. Id still have the layouts in a folder structure of pages.

For the navs, html.A in pattern-matching format.

To populate info to the content layer, use pattern-matching ALL and add the target layout to the content layer children using gap and flex css. This would allow for any number of layouts to exist in the content layer based upon what you click.

Then on each of the content’s children, I’d have a close button used that you can remove that child from the layout.

I know this is very vague, I currently cannot write this out, hopefully I explained it enough. I can write it out in a few hours.

1 Like

This would require the least rework :slight_smile: good job

1 Like

Took me a little longer to do it, but here is how this works:

import dash
from dash import html, dcc, Dash, Input, Output, ALL, State, ctx

app = Dash(__name__, use_pages=True)

app.layout = html.Div(
    [
        # main app framework
        html.Div("Testing", style={'fontSize':50, 'textAlign':'center'}),
        html.Div([
            html.A(page['name']+"  |  ", id={'index':page['name'], 'type':'childrenLinks'},
                   style={'cursor':'pointer'}, n_clicks=0)
            for page in dash.page_registry.values()
        ]),
        html.Hr(),
        html.Div(id='childrenContent', children=[], style={'display':'flex', 'alignItems':'stretch',
                                                           'alignContent':'stretch', 'gap':'10px'}),
        # # content of each page
        dash.page_container
    ]
)

@app.callback(
    Output('childrenContent','children'),
    Input({'index':ALL, 'type':'childrenLinks'}, 'n_clicks'),
    Input({'index':ALL, 'type':'removeButton'}, 'n_clicks'),
    State('childrenContent','children'),
)
def childrenContent(n, b, c):
    if ctx.triggered:
        if ctx.triggered_id.type == 'childrenLinks':
            for page in dash.page_registry.values():
                if page['name'] == ctx.triggered_id.index:
                    newLayout = page['layout']
                    newId, newButton = {'index':sum(n), 'type':'addedChildren'}, \
                                       html.Button('X', id={'index':sum(n), 'type':'removeButton'},
                                                   style={'position':'absolute', 'right':'0', 'padding':'5'})
                    try:
                        c.append(html.Div([newButton, newLayout()], id=newId, style={'flexGrow':'1', 'position':'relative'}))
                    except:
                        c.append(html.Div([newButton, newLayout], id=newId, style={'flexGrow':'1', 'position':'relative'}))
        else:
            for child in c:
                if child['props']['id']['index'] == ctx.triggered_id.index:
                    c.remove(child)
        return c
    return dash.no_update

if __name__ == "__main__":
    app.run(debug=True, port=12345)


note: There is probably a better way to have this interact, like having a dedicated page where this interact exists instead of the overall layout. :slight_smile:

You could even use it where you want to have the interactions be driven from a dropdown or accordion of the page.

1 Like

thank for your answer, I will try it

1 Like