Blazor - CRUD com EF Core e Modals (NET 6) - II
 Neste post vamos iniciar uma série de tutoriais para mostrar como criar uma aplicação Blazor Server e realizar o CRUD usando o EF Core e outros recursos no ambiente do  .NET 6.


Continuando o artigo anterior vamos agora realizar a validação da entrada do usuário, salvar os dados no banco de dados e atualizar os dados na página para exibir um novo registro.
...
 


 


 

Para realizar a validação vamos usar o recurso Data Annotations e assim vamos definir os atributos no modelo de domínio Tarefa conforme abaixo:

 

public class Tarefa
{
    [Key]
    public int Id { get; set; }

    [Required(ErrorMessage = "Informe o nome")]
    [StringLength(80, ErrorMessage = "Nome muito longo.")]

    public string? Nome { get; set; }

    [Required(ErrorMessage = "Informe o status")]
    public string? Status { get; set; }

    [Required(ErrorMessage = "Informe a data")]
    public DateTime ConclusaoEm { get; set; }
}

A seguir vamos usar os componentes :

  1. ValidationSummary - Resume as mensagens de validação;
  2. ValidationMessage - Exibe as mensagens de erro para uma entrada específica no formulário;

Para exibir as mensagens de validação no componente TarefaDetalhes.razor vamos incluir estes componentes :

@inject ITarefaService service

<div class="modal" tabindex="-1" role="dialog" id="tarefaModal">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">@Cabecalho</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">×</span>
                </button>

            </div>
            <div class="modal-body">
                <EditForm Model="@TarefaObj" OnValidSubmit="@HandleValidSubmit">

              <
DataAnnotationsValidator />
                    <div class="form-group mt-2 mb-2">
                        <label for="Nome">Nome</label>
                        <input type="hidden" @bind-value="@TarefaObj.Id" />
                        <InputText id="name" class="form-control" @bind-Value="@TarefaObj.Nome" />
                  <ValidationMessage For="@(() => TarefaObj.Nome)" />
                    </div>
                    <div class="form-group mb-2">
                        <label for="status">Status</label>
                        <InputSelect id="Summary" class="form-control"  @bind-Value="TarefaObj.Status">
                            <option value="">Selecione</option>
                            @foreach (var status in TarefaStatus)
                            {
                                    <option value="@status">
                                        @status
                                    </option>
                            }

                        </InputSelect>
                           
<ValidationMessage For="@(() => TarefaObj.Status)" />
                    </div>
                    <div class="form-group mb-3 mt-3">
                        <label for="ConclusaoEm">Conclusão em : </label>
                        <input type="date" id="addition" name="math" @bind-value="@TarefaObj.ConclusaoEm" />
                  <ValidationMessage For="@(() => TarefaObj.ConclusaoEm)" />
                    </div>
                    <button type="submit" class="btn btn-primary">Envia</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancela</button>
                </EditForm>
            </div>
        </div>
    </div>
</div>

@code {
       ...
}

Após essas alterações ao tentar enviar um formulário com dados inválidos teremos o seguinte resultado:

Salvando os Dados

Após receber os dados e realizara a validação temos que salvar os dados no banco de dados.  Para isso vamos usar o método HandleValidSubmit que é acionado quando o formulário é enviado com sucesso após passar na validação. Temos que adicionar a lógica “para salvar os dados” neste método.

private async void HandleValidSubmit()
{
   await service.Add(TarefaObj);
}

Usando a Interoperabilidade JavaScript

Os dados são salvos no banco de dados, mas a caixa de diálogo modal ainda está aberta. Precisamos chamar o código JavaScript a partir do código .NET para fechar a caixa de diálogo. Para chamar a função JavaScript do C#, vamos usar a abstração IJSRuntime.

O método InvokeAsync<T> usa um identificador para a função JavaScript que você deseja invocar junto com qualquer número de argumentos serializáveis por JSON.

Primeiro, temos que criar um método JavaScript para fechar a caixa de diálogo de bootstrap obtendo o id da caixa de diálogo. A segunda é injetar o IJSRuntime e, por último, usar o objeto injetado para emitir chamadas de interoperabilidade JavaScript.

O código JavaScript a seguir deve ser criado na pasta wwwroot dentro da subpasta js em um arquivo Utils.js :

function ShowModal(modalId) {
    $('#' + modalId).modal('show');
}
function CloseModal(modalId) {
    $('#' + modalId).modal('hide');
}

A seguir vamos incluir no arquivo _Layout.cshtml o código indicando o arquivo Javascript criado :

...

    @RenderBody()

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
  
 <script src="~/js/utils.js"></script>
    <script src="_framework/blazor.server.js"></script>
</body>
</html>

 

E no componente TarefaDetalhes.razor vamos alterar o  código conforme abaixo:

@inject ITarefaService service;
@inject IJSRuntime js;

...
...

@code {
    [Parameter]
    public Tarefa TarefaObj { get; set; }

    List<string> TarefaStatus = new List<string>() { "Nova", "Em andamento", "Concluída" };

    private async Task CloseTarefaModal()
    {
        await js.InvokeAsync<object>("CloseModal", "tarefaModal");
    }

    private async void HandleValidSubmit()
    {
            await service.Add(TarefaObj);
    }
}

Fazendo a comunicação entre componentes

Agora os dados estão salvos e a janela modal está fechada, mas não consiguimos ver o item recém-adicionado na lista de tarefas. Podemos ver os dados somente se atualizarmos o navegador.

Assim temos que dizer ao componente pai para se atualizar para exibir o novo conjunto de dados. Os componentes podem oferecer retornos de chamada que os componentes pai podem usar para reagir a eventos gerados por seus componentes filho.

Para isso vamos declarar uma Action AlteracaoDados e a invocar no método HandleValidSubmit do componente TarefaDetalhes.razor

@code {
    [Parameter]
    public Tarefa TarefaObj { get; set; }

   [Parameter]
    public Action AlteracaoDados { get; set; }

    List<string> TarefaStatus = new List<string>() { "Nova", "Em andamento", "Concluída" };

    private async Task CloseTarefaModal()
    {
        await js.InvokeAsync<object>("CloseModal", "tarefaModal");
    }

    private async void HandleValidSubmit()
    {
        await service.Add(TarefaObj);
         await CloseTarefaModal();
        AlteracaoDados?.Invoke();
    }
}

Desta forma o componente Tarefas.razor pode tratar o evento AlteracaoDados da seguinte forma:

...

<TarefaDetalhes TarefaObj=tarefaObject AlteracaoDados="@AlteracaoDados">
</TarefaDetalhes>

@code {
    List<Tarefa> tarefas;
    Tarefa tarefaObject = new Tarefa();
    string cabecalho = string.Empty;

    protected override async Task OnInitializedAsync()
    {
        tarefas = await service.Get();
    }

    private void InitializeTarefaObject()
    {
        tarefaObject = new Tarefa();
        tarefaObject.ConclusaoEm = DateTime.Now;
        cabecalho = "Nova Tarefa";
    }
  
   private async void AlteracaoDados()
   {
       tarefas = await service.Get();
       StateHasChanged();
   }

}

Com isso, podemos adicionar um novo registro após a validação, fechar a caixa de diálogo ao salvar e atualizar o componente pai.

Muuito bom !!!

Na próxima parte do artigo vamos continuar implementando a edição e a exclusão de tarefas ...

"Estejam vigilantes, mantenham-se firmes na fé, sejam homens de coragem, sejam fortes."
1 Coríntios 16:13

Referências:


José Carlos Macoratti