Добавление нового дочернего элемента данных с помощью Razor Pages, AJAX и Entity Framework Core - PullRequest
0 голосов
/ 23 января 2020

Исходя из ASP. NET Веб-форм и чувствуя себя немного перегруженными. У меня есть ASP. NET Core Razor Page, который загружает инцидент и все комментарии, связанные с этим инцидентом. Я понял, как обновить sh комментарии с частичной страницей Razor и AJAX, но также хочу добавить новый комментарий с AJAX и обновить sh комментарии.

Модели:

public class Incident
{
    public Incident()
    {
        Comments = new HashSet<Comment>();
    }

    public int Id { get; set; }

    public string Title { get; set; }

    public virtual ICollection<Comment> Comments { get; set; }
}

public class Comment
{
    public int IncidentId { get; set; }
    public int Id { get; set; }

    public string CommentText { get; set; }

    public virtual Incident Incident { get; set; }
}

Incident.cs html:

@page
@model MyNamespace.IncidentModel

@{
    ViewData["Title"] = "Emergency Operations Center";
}

<h4>@Html.DisplayFor(model => model.Incident.Title)</h4>
@Html.HiddenFor(model => model.Incident.Id)

<hr />

<form method="post" data-ajax="true" data-ajax-method="post">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>

    <div class="row">
        <input type="hidden" asp-for="Incident.Id" />
        <div class="col form-group">
            <label asp-for="NewComment.CommentText" class="control-label"></label>
            <input asp-for="NewComment.CommentText" class="form-control" />
            <span asp-validation-for="NewComment.CommentText" class="text-danger"></span>
        </div>
        <div class="col form-group">
            <label asp-for="NewComment.EocDept" class="control-label"></label>
            <input asp-for="NewComment.EocDept" class="form-control" />
            <span asp-validation-for="NewComment.EocDept" class="text-danger"></span>
        </div>
        <div class="col-auto form-group align-self-end">
            <input type="submit" value="Add Comment" class="btn btn-primary" />
        </div>
    </div>
</form>

<button id="getComments" class="btn btn-sm btn-outline-primary"><i class="fas fa-sync-alt"></i> Refresh Comments</button>
<div id="comments" class="mt-3">
    <partial name="_CommentsPartial" model="Model.Incident.Comments.ToList()" />
</div>

<div class="mt-4">
    <a asp-page="./Index">Back to Incident list</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script>
        $(function () {
            $('#getComments').on('click', function () {
                $('#comments').load('/Incident?handler=CommentsPartial&id=' + @Model.Incident.Id.ToString());
            });
        });
    </script>
}
@model List<Models.Comment>

<table class="table table-sm table-striped">
    <thead>
        <tr>
            <th>@Html.DisplayNameFor(model => model.FirstOrDefault().EocDept)</th>
            <th>@Html.DisplayNameFor(model => model.FirstOrDefault().EnterDateTime)</th>
            <th>@Html.DisplayNameFor(model => model.FirstOrDefault().EnteredBy)</th>
            <th>@Html.DisplayNameFor(model => model.FirstOrDefault().CommentText)</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@Html.DisplayFor(modelItem => item.EocDept)</td>
                <td>@Html.DisplayFor(modelItem => item.EnterDateTime)</td>
                <td>@Html.DisplayFor(modelItem => item.EnteredBy)</td>
                <td>@Html.DisplayFor(modelItem => item.CommentText)</td>
            </tr>
        }
    </tbody>
</table>

Модель страницы в Incident.cs html .cs

public class IncidentModel : PageModel
{
    private readonly MyDbContext _context;

    public IncidentModel(MyDbContext context)
    {
        _context = context;
    }

    public Incident Incident { get; set; }

    [BindProperty]
    public Comment NewComment { get; set; }

    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
            return NotFound();

        Incident = await _context.Incidents.FirstAsync(m => m.Id == id);

        if (Incident == null)
            return NotFound();

        LoadSortedComments();

        return Page();
    }

    public async Task<PartialViewResult> OnGetCommentsPartialAsync(int id)
    {
        Incident = await _context.Incidents.FirstAsync(m => m.Id == id);

        LoadSortedComments();

        return Partial("_CommentsPartial", Incident.Comments.ToList());
    }

    public void LoadSortedComments()
    {
        var entry = _context.Entry(Incident);
        entry.Collection(e => e.Comments)
            .Query()
            .OrderByDescending(c => c.EnterDateTime)
            .Load();
    }

    public async Task<IActionResult> OnPost(int id)
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        // Is this the correct way to add the new Comment?
        NewComment.IncidentId = id;
        _context.Comments.Add(NewComment);
        await _context.SaveChangesAsync();

        // How do I refresh _CommentsPartial, and what gets returned here?
        return ?????;
    }
}

Вопросы:

  1. Правильно ли использовать свойство bound NewComment для получения нового комментария? (В любом случае, он добавляется в базу данных.)
  2. Является ли получение идентификатора инцидента из параметра в OnPost правильным способом ссылки на инцидент страницы?
  3. Что я возвращаю из OnPost если я не хочу перезагрузить всю страницу?

1 Ответ

1 голос
/ 23 января 2020

Вы можете загрузить связанные данные, используя Include, как показано ниже;

public async Task<IActionResult> OnGetAsync(int? id)
{
        if (id == null)
            return NotFound();

        Incident = await _context.Incidents.Include(i=>i.Comments).FirstOrDefaultAsync(m => m.Id == id);

        if (Incident == null)
            return NotFound();

        return Page();
}

Вы можете добавить связанный объект , как показано ниже

 public async Task<IActionResult> OnPost(int id)
 {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        Incident = await _context.Incidents.Include(i=>i.Comments).FirstAsync(i => i.Id == id);

        NewComment.EnterDateTime = DateTime.Now;
        Incident.Comments.Add(NewComment);
        await _context.SaveChangesAsync();
        return RedirectToPage("Incident","", new { id= Incident.Id});
  }

Что мне вернуть из OnPost, если я не хочу перезагружать всю страницу?

Вы можете добавить data-ajax-success в форму и добавить функцию, как показано ниже:

<form method="post" data-ajax="true" data-ajax-method="post" data-ajax-complete="successed">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>

<div class="row">
    <input type="hidden" asp-for="Incident.Id" />
    <div class="col form-group">
        <label asp-for="NewComment.CommentText" class="control-label"></label>
        <input asp-for="NewComment.CommentText" class="form-control" />
        <span asp-validation-for="NewComment.CommentText" class="text-danger"></span>
    </div>
    <div class="col form-group">
        <label asp-for="NewComment.EocDept" class="control-label"></label>
        <input asp-for="NewComment.EocDept" class="form-control" />
        <span asp-validation-for="NewComment.EocDept" class="text-danger"></span>
    </div>
    <div class="col-auto form-group align-self-end">
        <input id="" type="submit" value="Add Comment" class="btn btn-primary" />
    </div>
</div>
</form>

@section Scripts {
  <script type="text/javascript" src="~/lib/jquery-validation-unobtrusive/jquery.unobtrusive-ajax.js"></script>
  <script>
    successed = function (result) {
        $('#comments').html(result);
    }
  </script>
}

Ссылка: https://www.learnrazorpages.com/razor-pages/ajax/unobtrusive-ajax

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...