Blazor - Despesas Pessoais com Gráfico de Barras e Pizza - III
Neste artigo vamos iniciar a criação de uma aplicação Blazor Web Assemply para gerenciar despesas pessoais onde vamos criar gráficos de barras e de pizza. |
Continuando a segunda parte do artigo vamos exibir as despesas, implementar o formulário de Despesas e a exclusão de uma receita/despesa.
Exibindo as despesas
Vamos agora exibir as despesas criando na pasta Pages o componente Despesas.razor usando o mesmo procedimento e lógica que foi usado para implementar o componente Receitas.razor.
Nota: Em outro artigo poderei mostrar como otimizar a aplicação removendo esta lógica duplicada.
No projeto Client na pasta Pages crie o componente Despesas.razor :
@page "/despesas" @inject HttpClient Http;
<div
class="row">
protected async Task CarregaDados()
public async Task Refresh() |
Criando o formulário de despesas
A seguir na pasta Components crie o componente DespesaForm.razor :
@inject HttpClient Http;
<div class="card">
<div class="card-header" style="background-color: sandybrown; font-weight: bold">
Incluir despesa
</div>
<div class="card-body">
<EditForm Model="@despesa" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group">
<label for="datainput">Data</label>
<InputDate class="form-control" id="datainput" @bind-Value="despesa.Data" />
</div>
<div class="form-group">
<label for="descricaoinput">Descrição</label>
<InputText class="form-control" id="descricaoinput" @bind-Value="despesa.Descricao" />
</div>
<div class="form-group">
<label for="categoriainput">Categoria</label>
<InputSelect class="form-control" id="categoriainput" @bind-Value="despesa.Categoria">
@{
foreach (var value in Enum.GetValues(typeof(CategoriaDespesa)))
{
<option value="@value">@value</option>
}
}
</InputSelect>
</div>
<div class="form-group">
<label for="valorinput">Valor</label>
<InputNumber class="form-control" id="valorinput" @bind-Value="despesa.Valor" />
</div>
<div>
<button type="submit" class="btn btn-primary">Enviar</button>
</div>
</EditForm>
</div>
</div>
@code{
private DespesaDTO despesa = new DespesaDTO { Data = DateTime.Today };
[Parameter]
public EventCallback OnSubmitCallback { get; set; }
public async Task HandleValidSubmit()
{
await Http.PostAsJsonAsync<DespesaDTO>("api/Despesas", despesa);
await OnSubmitCallback.InvokeAsync();
}
}
|
Com isso já temos a exibição dos dados das receitas e despesas e dos respectivos formulários concluídos.
Executando o projeto teremos:
Agora vamos implementar a exclusão de receita e despesa.
Implementando a exclusão de receita e despesa
Vamos agora implementar a exclusão de uma receita ou despesa quando o usuário clica no botão Excluir nos componentes Receitas.razor e Despesas.razor.
Vamos usar uma janela de diálogo Modal para solicitar a confirmação do usuário antes de realizar a exclusão. Para isso vamos criar na pasta Components o componente ModelDialog.razor :
<div class="modal fade show" id="myModal"
style="display:block; background-color: rgba(10,10,10,.8);" aria-modal="true"
role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">@Title</h4> <button type="button" class="close" @onclick="@ModalCancel">×</button> </div> <div class="modal-body"> <p>@Text</p> </div> <div class="modal-footer"> @switch (DialogType) { case ModalDialogType.Ok: <button type="button" class="btn btn-primary" @onclick=@ModalOk>OK</button> break; case ModalDialogType.OkCancel: <button type="button" class="btn" @onclick="@ModalCancel">Cancela</button> <button type="button" class="btn btn-primary" @onclick=@ModalOk>OK</button> break; case ModalDialogType.DeleteCancel: <button type="button" class="btn" @onclick="@ModalCancel">Cancela</button> <button type="button" class="btn btn-danger" @onclick=@ModalOk>Deleta</button> break; } </div> </div> </div> </div> @code { [Parameter] public EventCallback<bool> OnClose { get; set; }
[Parameter]
[Parameter]
[Parameter]
private Task ModalCancel() |
Definimos um parâmetro do tipo EventCallback novamente e também usamos o argumento de tipo genérico e definimos a propriedade OnClose como EventCallback de boolean.
Implementamos um
método privado ModalCancel onde usamos o retorno de
chamada OnClose e chamamos seu método
InvokeAsync e fornecemos false como seu
argumento.
A seguir, implementamos um método ModalOk usando o
retorno de chamada OnClose e chamamos seu método
InvokeAsync. No entanto, desta vez, fornecemos
true como argumento.
Para o botão Fechar adicionamos o atributo onclick
e usamos o método ModalCancel e fazemos o mesmo
para o botão OK, exceto que vinculamos o método
ModalOk.
Como queremos construir um componente que possa ser usado em diferentes lugares do aplicativo não podemos implementar código específico de negócios neste componente.
Para tornar mais flexível o uso das janelas de diálogos implementamos também o tipo de diálogo que desejamos exibir criando a enumeração ModelDialogType.cs na pasta Components:
public enum ModalDialogType
{
Ok,
OkCancel,
DeleteCancel
}
|
Definimos os parâmetros para o Titulo o Texto e o botão de Cancelar e passamos o tipo de diálogo que desejamos exibir.
Agora teremos que ajustar o código dos componentes Receitas.razor e Despesas.razor definindo os seguintes ajustes:
1- No botão Excluir vamos a chamada do método OpenDeleteDialog()
<td><button type="button" class="btn btn-danger btn-sm" @onclick="() => OpenDeleteDialog(despesa)">Excluir</button></td> |
<td><button type="button" class="btn btn-danger btn-sm" @onclick="() => OpenDeleteDialog(receita)">Excluir</button></td> |
2- Incluir o código que vai usar o componente ModelDialog para exibir o tipo de janela de diálogo:
@if (DeleteDialogOpen) { <ModelDialog Title="Confirma ?" Text="Deseja excluir este item ?" OnClose="@OnDeleteDialogClose" DialogType="ModalDialogType.DeleteCancel"/> } |
3- Implementar o código dos métodos OpenDeleteDialog e OnDeleteDialogClose para receita e despesa:
private async Task OnDeleteDialogClose(bool accepted)
{
if (accepted)
{
await Http.DeleteAsync($"api/Receitas/{_receitaDeleta.Id}");
await CarregaDados();
_receitaDeleta = null;
}
DeleteDialogOpen = false;
}
private void OpenDeleteDialog(Receita receita)
{
_receitaDeleta = receita;
DeleteDialogOpen = true;
}
|
private async Task OnDeleteDialogClose(bool accepted)
{
if (accepted)
{
await Http.DeleteAsync($"api/Despesas/{_despesaDeleta.Id}");
await CarregaDados();
_despesaDeleta = null;
}
DeleteDialogOpen = false;
}
private void OpenDeleteDialog(Despesa despesa)
{
_despesaDeleta = despesa;
DeleteDialogOpen = true;
}
}
|
Com isso já podemos testar a exclusão de receitas usando as janela de diálogos modais para confirmar a exclusão:
Na próxima parte do artigo vamos criar o dashboard para exibir os gráficos de barras e de pizza.
"Brame o mar e a
sua plenitude; o mundo, e os que nele habitam.
Os rios batam as palmas; regozijem-se também as montanhas,
Perante a face do Senhor, porque vem a julgar a terra; com justiça julgará o
mundo, e o povo com eqüidade."
Salmos 98:7-9
Referências:
ASP .NET Core - Implementando a segurança com
ASP.NET Core MVC - Criando um Dashboard .
C# - Gerando QRCode - Macoratti
ASP .NET - Gerando QRCode com a API do Google
ASP .NET Core 2.1 - Como customizar o Identity
Usando o ASP .NET Core Identity - Macoratti
ASP .NET Core - Apresentando o IdentityServer4
ASP .NET Core 3.1 - Usando Identity de cabo a rabo