Razor Pages - Updating a Model with AJAX and PartialView

I'm starting to study Razor Pages and using MongoDB as my database.

I finished my CRUD operations, and now I'm working on my main page.

Main Page

But I can't understand how to update partially my page

the first search (Default taking DateTime.Now) is already working as expected, but when I change the month selector, my page doesn't update with the current list I'm working with.

I'm using AJAX for this POST method on my View:

(ContaView.cshtml)

@page
@using System.Globalization
@model ControleContas.Pages.Contas.ContasViewModel
@{
}

<script>
    function changeDateSelector(date){
        var dataAtualizada = date.value;
        $.ajax({
            type: "POST",
            url: '/Contas/ContaView?handler=MonthSelector',
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: JSON.stringify(dataAtualizada),
            headers:
            {
                "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val()
            }
        });
    }
</script>

<div>
    <a class="nav-link text-dark" asp-area="" asp-page="/Contas/ContaCadastro"><button type="button" class="btn btn-primary">Cadastrar Cartão</button></a>
</div>

<th scope="row"><button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#CreateModal">Criar</button></th>
<br />
<div id="titleMonth">@Model.dataCorrente.ToString("MMMM", CultureInfo.CreateSpecificCulture("pt-br"))</div>
<br />
<button type="button" class="btn btn-light">&larr;</button>
<input min="@(DateTime.Now.AddYears(-10).ToString("yyyy-MM"))" max="@(DateTime.Now.AddYears(10).ToString("yyyy-MM"))" onchange="changeDateSelector(this)" asp-for="dataCorrente" type="month">
<button type="button" class="btn btn-light">&rarr;</button>

<!-- Modal -->
<div class="modal fade" id="CreateModal" tabindex="-1" role="dialog" aria-labelledby="CreateTitle" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="CreateTitle">Criar Conta</h5>
                <button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <form method="post">
                <div class="modal-body">
                    <input id="UserModal" hidden="hidden"></input>
                    <div class="form-group">
                        <label>Nome da Conta</label>
                        <input id="ValorCreateModal" asp-for="conta.Nome" type="text" class="form-control" placeholder="Nome" />
                    </div>
                    <div class="form-group">
                        <label>Valor</label>
                        <input id="ValorCreateModal" asp-for="conta.Valor" type="text" class="form-control" placeholder="Valor" />
                    </div>
                    <div class="form-group">
                        <label>Data</label>
                        <input id="DataCreateModal" asp-for="conta.Data" type="date" class="form-control" placeholder="Data da Conta" />
                    </div>
                    <div class="form-group">
                        <label>Prestações</label>
                        <input id="PrestacoesCreateModal" asp-for="conta.TotalPrestacoes" type="number" class="form-control" placeholder="Insira aqui a Quantidade de Prestações (1 - à Vista)" />
                    </div>
                    <div class="form-group">
                        <label>Pago?</label>
                        <input id="DespesaCreateModal" asp-for="conta.Pago" type="checkbox" class="form-control" />
                    </div>
                    <div class="form-group">
                        <label>Despesa?</label>
                        <input id="DespesaCreateModal" asp-for="conta.Despesa" type="checkbox" class="form-control" />
                    </div>
                    <!--
                        TODO: Criar um CheckBox para identificar se é uma conta para cartão, se for habilitar Selection para apresentar os cartões e assim vincular ele se não, vincular ao identity Logado.
                     <div class="form-group">
                        <label>Cartão?</label>
                        <input id="FimCartaoModal" type="text" class="form-control" placeholder="Fim Cartão" />
                    </div>-->
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                    <button type="submit" asp-page-handler="create" class="btn btn-primary">Save</button>
                </div>
            </form>
        </div>
    </div>
</div>

<table class="table">
    <tr>
        <th>Id</th>
        <th>Nome</th>
        <th>Valor</th>
        <th>Data</th>
        <th>Prestação</th>
        <th>Cartão</th>
        <th>Pago?</th>
        <th>Despesa?</th>
        <th></th>
        <th></th>
    </tr>
    @foreach (var conta in Model.contas)
    {
        <tr>
            <th>@conta._id</th>
            <th>@conta.Nome</th>
            <th>@conta.Valor</th>
            <th>@conta.Data.ToShortDateString()</th>
            <th>@(conta.TotalPrestacoes == 1 ? "" : $"{conta.PrestacaoAtual}/{conta.TotalPrestacoes}")</th>
            <th>@conta.CartaoId</th>
            <th>@(conta.Pago ? "Sim" : "Não")</th>
            <th>@(conta.Despesa ? "Sim" : "Não")</th>
            <th><button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#CreateModal">Editar</button></th>
            <th><button type="button" class="btn btn-danger">Deletar</button></th>
        </tr>
    }
</table>

ContaView.cshtml.cs

using ControleContas.DTO.Contas;
using ControleContas.Models.Contas;
using ControleContas.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;

namespace ControleContas.Pages.Contas
{
    public class ContasViewModel : PageModel
    {
        private readonly ContaDTO contaDTO;

        [BindProperty]
        public List<Conta> contas { get; set; }

        [BindProperty]
        public Conta conta { get; set; }

        [BindProperty]
        [DataType(DataType.Date)]
        public DateTime dataCorrente { get; set; } = DateTime.Now;

        public ContasViewModel(IConfiguration config)
        {
            this.contaDTO = new ContaDTO(config);
        }

        public void OnGet()
        {
            contas = BuscarContasUsuarioMes(User.Identity.Name, dataCorrente);
        }

        public IActionResult OnPostCreate()
        {
            conta.NomeUsuario = User.Identity.Name;
            if(conta.TotalPrestacoes > 1)
            {
                var dataBase = conta.Data;
                List<Conta> prestacoesContas = new List<Conta>();
                for (int i = 0; i < conta.TotalPrestacoes; i++)
                {
                    var contaPrestacao = new Conta
                    {
                        CartaoId = conta.CartaoId,
                        Despesa = conta.Despesa,
                        NomeUsuario = conta.NomeUsuario,
                        Nome = conta.Nome,
                        Pago = false,
                        PrestacaoAtual = i + 1,
                        Valor = conta.Valor,
                        TotalPrestacoes = conta.TotalPrestacoes,
                        Data = dataBase
                    };
                    dataBase = dataBase.AddMonths(1);
                    prestacoesContas.Add(contaPrestacao);
                }
                contaDTO.CreateMany(prestacoesContas, contaDTO.Database, contaDTO.ContaCollection);
            }
            else
            {
                conta.PrestacaoAtual = 1;
                conta.Pago = false;
                contaDTO.Create(conta, contaDTO.Database, contaDTO.ContaCollection);
            }
            return Redirect("ContaView?data=" + dataCorrente.Year + dataCorrente.Month);
        }

        public PartialViewResult OnPostMonthSelector([FromBody] string dataAtualizada)
        {
            dataCorrente = DateTime.ParseExact(dataAtualizada, "yyyy-MM", null);
            contas = BuscarContasUsuarioMes(User.Identity.Name, dataCorrente);
            return Partial("ContaView", contas);
        }

        private List<Conta> BuscarContasUsuarioMes(string user, DateTime data)
        {
            return contaDTO.buscaContasUsuario(user).Where(c => c.Data.Month == dataCorrente.Month && c.Data.Year == dataCorrente.Year).ToList();
        }
    }
}

I'm trying with the Partial() found around some sites, but Im not figuring out how to update my List of object <Conta> on my page.

Would like some help to understand this process

I know how to do this with the normal <form> processo on my month selector, but I'd like to learn how to do properly this ajax call (starter in front end, worked as only Back-end dev 3 years)

Using .NET Core 6.0

Make the page update the list with the date passed through ajax

Update: I did the changes to use the partial view but when the page loads it not recognize my model list, it finds the page on my project but still having null pointer, even tried passing manually a new List on the partial tag on HTML, but it does not find it.

I'm curious if Identity can interfere in any way

I checked some forums about, but I couldn't make it work

Prints:

Values on list

HTML TAG

Page location

Exception

Update 2: Everything was correct, but @page directive on PartialView page must not exists, just removing that and everything started to work fine.

Upvotes: 0

Views: 1080

Answers (1)

Yiyi You
Yiyi You

Reputation: 18159

You can try to use a partial view in Pages/Shared,replace the html in ajax success:

Pages/Shared/Partial:

@model List<Conta>
<table class="table">
    <tr>
        <th>Id</th>
        <th>Nome</th>
        <th>Valor</th>
        <th>Data</th>
        <th>Prestação</th>
        <th>Cartão</th>
        <th>Pago?</th>
        <th>Despesa?</th>
        <th></th>
        <th></th>
    </tr>
    @foreach (var conta in Model)
    {
        <tr>
            <th>@conta._id</th>
            <th>@conta.Nome</th>
            <th>@conta.Valor</th>
            <th>@conta.Data.ToShortDateString()</th>
            <th>@(conta.TotalPrestacoes == 1 ? "" : $"{conta.PrestacaoAtual}/{conta.TotalPrestacoes}")</th>
            <th>@conta.CartaoId</th>
            <th>@(conta.Pago ? "Sim" : "Não")</th>
            <th>@(conta.Despesa ? "Sim" : "Não")</th>
            <th><button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#CreateModal">Editar</button></th>
            <th><button type="button" class="btn btn-danger">Deletar</button></th>
        </tr>
    }
</table>

ajax:

 function changeDateSelector(date){
        var dataAtualizada = date.value;
        $.ajax({
            type: "POST",
            url: '/Contas/ContaView?handler=MonthSelector',
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(dataAtualizada),
            headers:
            {
                "RequestVerificationToken": $('input:hidden[name="__RequestVerificationToken"]').val()
            },
            success:function(data){
                $("#test").html(data);
            }
        });
    }

ContaView.cshtml:

<div id="test">
    <partial name="Partial" [email protected] />
</div>

ContaView.cshtml.cs:

public PartialViewResult OnPostMonthSelector([FromBody] string dataAtualizada)
        {
            dataCorrente = DateTime.ParseExact(dataAtualizada, "yyyy-MM", null);
            contas = BuscarContasUsuarioMes(User.Identity.Name, dataCorrente);
            return Partial("Partial", contas);
        }

Upvotes: 1

Related Questions