Im trying to use duplicate callback outputs, but it does not seem to work. The weird is that when I click the button with id BUTTON_ADD_EXPENSE, the popover shows, but the callback function is not called. Could you guys help me, please?
import dash
from dash import Dash, html, dcc, callback, Input, Output, State
import dash_bootstrap_components as dbc
from components import ids
from datetime import datetime, date
import pandas as pd
import json
dash.register_page(__name__)
def load_categories(cat = None):
categories_file = open("data/expenses_categories.json", "r+")
categories_data = json.load(categories_file)
if(cat is None):
return categories_data["categories"]
else:
categories_data["categories"].append(cat)
categories_file.seek(0)
json.dump(categories_data, categories_file, indent=4)
return categories_data["categories"]
cat_despesa = load_categories()
def layout() -> html.Div:
return dbc.Modal([
dbc.ModalHeader(dbc.ModalTitle("Adicionar despesa")),
dbc.ModalBody([
dbc.Row([
dbc.Col([
dbc.Label("Descrição: "),
dbc.Input(placeholder="Ex.: dividendos da bolsa, herança...", id=ids.EXPENSE_DESCRIPTION),
], width=6),
dbc.Col([
dbc.Label("Valor: "),
dbc.Input(placeholder="$100.00", id=ids.INPUT_EXPENSE_VALUE, value="")
], width=6)
]),
dbc.Row([
dbc.Col([
dbc.Label("Data: "),
dcc.DatePickerSingle(
id=ids.EXPENSE_DATE,
min_date_allowed=date(2020, 1, 1),
max_date_allowed=date(2030, 12, 31),
date=datetime.today(),
style={"width": "100%"}
),
], width=4),
dbc.Col([
dbc.Label("Número de parcelas:"),
dbc.Input(placeholder="Digite o número de parcelas", id=ids.NUMBER_OF_PARCELA, value="")
], width=4),
dbc.Col([
html.Label("Categoria da despesa"),
dbc.Select(id=ids.SELECT_EXPENSE_CATEGORY, options=[{"label": i, "value": i} for i in cat_despesa])
], width=4)
], style={"margin-top": "25px"}),
dbc.Row([
dbc.Accordion([
dbc.AccordionItem(children=[
dbc.Row([
dbc.Col([
html.Legend("Adicionar categoria", style={'color': 'green'}),
dbc.Input(type="text", placeholder="Nova categoria...", id=ids.INPUT_ADD_CATEGORY, value=""),
html.Br(),
dbc.Button("Adicionar", className="btn btn-success", id=ids.BUTTON_ADD_CATEGORY, style={"margin-top": "20px"}),
html.Br(),
html.Div(id="category-div-add-despesa", style={}),
], width=6),
dbc.Col([
html.Legend("Excluir categorias", style={'color': 'red'}),
dbc.Checklist(
id="checklist-selected-style-despesa",
options=[{"label": i, "value": i} for i in cat_despesa],
value=[],
label_checked_style={"color": "red"},
input_checked_style={"backgroundColor": "#fa7268", "borderColor": "#ea6258"},
),
dbc.Button("Remover", color="warning", id="remove-category-despesa", style={"margin-top": "20px"}),
], width=6)
])
])
]),
dbc.ModalFooter([
dbc.Button("Adicionar despesa", id=ids.BUTTON_ADD_EXPENSE),
dbc.Popover(dbc.PopoverBody("Despesa Salva"), target=ids.BUTTON_ADD_EXPENSE, placement="left", trigger="click")
])
], style={"margin-top": "25px"})
]),
],
style={"background-color": "rgba(17, 140, 79, 0.05)"},
id="modal-novo-despesa",
size="lg",
is_open=True,
centered=True,
backdrop=True
)
# Add/Remove categoria despesa
@callback(
[Output("category-div-add-despesa", "children"),
Output("category-div-add-despesa", "style"),
Output('checklist-selected-style-despesa', 'options'),
Output('checklist-selected-style-despesa', 'value'),
],
[Input(ids.BUTTON_ADD_CATEGORY, "n_clicks"),
Input("remove-category-despesa", 'n_clicks')],
[State(ids.INPUT_ADD_CATEGORY, "value"),
State('checklist-selected-style-despesa', 'value')]
)
def add_category(n, n2, txt, check_delete):
txt1 = []
style1 = {}
categories = None
if n:
if txt == "" or txt == None:
txt1 = "O campo de texto não pode estar vazio para o registro de uma nova categoria."
style1 = {'color': 'red'}
else:
categories = load_categories(txt)
categories = categories + [txt] if txt not in categories else categories
txt1 = f'A categoria {txt} foi adicionada com sucesso!'
style1 = {'color': 'green'}
if n2:
if len(check_delete) > 0:
categories = [i for i in categories if i not in check_delete]
if categories is not None:
opt_despesa = [{"label": i, "value": i} for i in categories]
return [txt1, style1, opt_despesa, opt_despesa]
else:
opt_despesa = [{"label": i, "value": i} for i in cat_despesa]
return [txt1, style1, opt_despesa, opt_despesa]
@callback(
Output(ids.TABLE, 'data', allow_duplicate=True),
Input(ids.BUTTON_ADD_EXPENSE, 'n_clicks'),
[
State(ids.INPUT_EXPENSE_VALUE, "value"),
State(ids.NUMBER_OF_PARCELA, "value"),
State(ids.EXPENSE_DESCRIPTION, "value"),
State(ids.EXPENSE_DATE, "date"),
State(ids.SELECT_EXPENSE_CATEGORY, "value"),
State(ids.TABLE, 'data')
],
prevent_initial_call=True
)
def salve_form_despesa(n, valor, valor_parcelas, descricao, date, categoria, dict_despesas):
print("carregado!")
df_despesas = pd.DataFrame(dict_despesas)
# print(df_despesas)
print("===========================================")
if n and not(valor == "" or valor== None):
valor = float(valor)
valor = round(valor, 2)
date = pd.to_datetime(date).date()
categoria = categoria[0] if type(categoria) == list else categoria
if descricao == None or descricao == "":
descricao = 0
# df_despesas.loc[df_despesas.shape[0]] = [valor, recebido, fixo, date, descricao, categoria]
# print(df_despesas)
# update_index_despesas(df_despesas)
data_return = df_despesas.to_dict()
return data_return