Hello,
First of all, I’m a great fan of Dash. It is amazing and I.m learning everyday about it.
Currently I got stuck with a problem for few days and looking a working solution for it.
I’m populating a Dash datatable but the pagination buttons are not placed correctly. I’m using Dash login framework and added a new page where the datatable resides.
Scenario 1:
- The datatable is loaded with pagination_mode=‘be’ [Ref: https://dash.plot.ly/datatable/callbacks]. With the update_table(pagination_settings) callback, it is loading the data. But the pagination buttons are placed after the first row. So if the table is having more than one row, the buttons are been covered by the rows and become invisible (unless you delete all the rows):
***With page size set as 3
***With rows deleted:
- If pagination_mode=‘fe’ is been used [Ref: https://dash.plot.ly/datatable/interactivity] along with callback, then it does not load any data in the table and no pagination button as well.
I’m not sure what I’m doing wrong. I tried to change possible all the CSS (classname) to make the desired effect and failed shamelessly before raising this request in here. Could somebody please help!
Below is the code for the same:
USER_TABLE.py
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from server import app, User
from flask_login import current_user
from werkzeug.security import check_password_hash
import dash
import dash_table
import pandas as pd
import sqlite3
import users_mgt
conn = sqlite3.connect("users.db", check_same_thread=False)
df = pd.read_sql_query("select username, email, (select replace(password, (select password from user), '****') from user) as password from user;", conn)
PAGE_SIZE = 3
layout = html.Div(
id='editable_datatable_container',
className="datatable-container",
n_clicks=0,
style={'text-transform':'uppercase'},
children=[
dash_table.DataTable(
id='editable-table',
columns=[{"name": i, "id": i, 'deletable': True} for i in df.columns],
data=df.to_dict('records'),
pagination_mode='fe',
editable=True,
row_selectable='multi',
row_deletable=True,
style_cell={'textAlign': 'left'},
style_cell_conditional=[
{
'if': {'row_index': 'odd'},
'backgroundColor': 'rgb(248, 248, 248)'
}
],
style_header={
'backgroundColor': 'rgb(248, 248, 248)',
'fontWeight': 'bold'
},
style_data_conditional=[{
"if": {"row_index": 1},
"backgroundColor": "rgb(0, 151, 58)",
'color': 'white'
}],
pagination_settings={
'current_page': 0,
'page_size': PAGE_SIZE,
},
css=[
{ 'selector': '.previous-page, .next-page', 'rule': 'background-color: rgb(0, 151, 58);' }
],
#navigation="page",
),
dcc.ConfirmDialog(
id='confirm',
message='Danger danger! Are you sure you want to continue?',
),
html.Div(id='output')
]
),
#Datatable Pagination
@app.callback(
Output('editable-table', 'data'),
[Input('editable-table', 'pagination_settings')])
def update_table(pagination_settings):
return df.iloc[
pagination_settings['current_page']*pagination_settings['page_size']:
(pagination_settings['current_page'] + 1)*pagination_settings['page_size']
].to_dict('records')
# Callback for making datatable editable
@app.callback(Output('output', 'children'),
[Input('editable-table', 'data_previous')],
[State('editable-table', 'data')])
def show_removed_rows(previous, current):
if previous is None:
print ('No previous row is selected')
dash.exceptions.PreventUpdate()
else:
#return [f'Just removed {row}' for row in previous if row not in current]
if current_user.username == 'admin':
return 'User deleted successfully'
else:
#return 'You do not have sufficient permission to delete user'
return ''
return ''
This USER_TABLE is been embedded within the Dash login framework which looks like this [app.py]:
index page
import os
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from server import app, server
from flask_login import logout_user, current_user
from views import success, dashboard, login, login_fd, logout, user, user_table
header = html.Div(
className='header',
children=html.Div(
className='header-width',
style={'height': '100%', 'width': '95%', 'margin-left':'auto', 'margin-right':'auto'},
children=[
html.Img(
src='assets/Marvin-Banner.svg',
className='logo'
),
html.Div(className='links', children=[
html.Div(id='dashboard', className='link'),
html.Div(id='add-user', className='link'),
html.Div(id='user-name', className='link'),
html.Div(id='logout', className='link')
])
]
)
)
app.layout = html.Div(
[
header,
html.Div([
html.Div(
html.Div(id='page-content', className='content'),
className='content-container',
),
], className='container-width-body', style={'height': '100%', 'width': '97%', 'margin-left':'auto', 'margin-right':'auto'},),
dcc.Location(id='url', refresh=False),
]
)
app.config.supress_callback_exceptions = True
@app.callback(Output('page-content', 'children'),
[Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/':
return login.layout
elif pathname == '/login':
return login.layout
elif pathname == '/dashboard':
if current_user.is_authenticated:
return dashboard.layout
else:
return login_fd.layout
elif pathname == '/logout':
if current_user.is_authenticated:
logout_user()
return logout.layout
else:
return logout.layout
elif pathname == '/user':
if current_user.is_authenticated:
return user.layout
else:
return login.layout
else:
return '404'
@app.callback(
Output('user-name', 'children'),
[Input('page-content', 'children')])
def cur_user(input1):
if current_user.is_authenticated:
return html.Div('Signed in: ' + current_user.username)
# 'User authenticated' return username in get_id()
else:
return ''
@app.callback(
Output('add-user', 'children'),
[Input('page-content', 'children')])
def add_user(input1):
if current_user.is_authenticated:
return html.A('Users', href='/user')
else:
return ''
if __name__ == '__main__':
#app.run_server(debug=True)
port = int(os.getenv('PORT', 8050))
app.run_server(debug=True, host='0.0.0.0', port=port, threaded=True)