#c# #asp.net-core-mvc #asp.net-core-3.1
#c# #asp.net-ядро-mvc #asp.net-ядро-3.1
Вопрос:
Я создаю Форум. Это ан ASP.NET Основное приложение 3.1 MVC.
В представлении индекса сообщений вверху есть заголовок и содержимое сообщения, а ответы на сообщения перечислены ниже с циклом foreach. Я хотел бы реализовать функции редактирования в одном и том же представлении без необходимости создавать новые отдельные представления.
Я уже создал функцию редактирования для этого поста. Когда пользователь нажимает кнопку «ИЗМЕНИТЬ» в сообщении, EditPostModal
появляется сообщение, и оно работает как заклинание. Это было довольно легкой задачей для меня, так как в одном представлении поста есть только один соответствующий пост.
Теперь я хотел бы сделать что-то подобное для каждого ответа. Проблема, с которой я столкнулся сейчас, заключается в том, что если я помещу новое модальное окно для редактирования ответов в тот же цикл foreach, который я использую для отображения ответов, я смогу получить доступ ко всем соответствующим свойствам для заполнения модальной информации, но это создает беспорядок. Во-первых, я думаю, что немного неуместно иметь один модальный для каждого ответа. Кроме того, теперь каждый модал является практически одним и тем же модалом, но с разной информацией (разным скрытым идентификатором и содержимым), и когда я нажимаю кнопку «Отправить», возникает исключение null для @reply.Id
, я предполагаю, потому что он пытается передать информацию из всех модалов сразу контроллеру в замешательстве.
С другой стороны, когда я помещаю это модальное окно за пределы цикла foreach, я не могу получить доступ к информации после ответа через модель. Или я просто не знаю, как этого добиться.
Пожалуйста, найдите код ниже (упрощенный, только соответствующие части).
Просмотр моделей:
public class PostIndexModel { public int Id { get; set; } public string Title { get; set; } public DateTime CreatedOn { get; set; } public string PostContent { get; set; } public IEnumerablelt;PostReplyModelgt; Replies { get; set; } } public class PostReplyModel { public int Id { get; set; } public DateTime CreatedOn { get; set; } public string ReplyContent { get; set; } }
Индекс просмотра сообщений.cshtml:
@model WebProjectAircraftForum.Models.Post.PostIndexModel lt;div class="container"gt; lt;div class="row PostIndex-PostContent"gt; lt;div class="PostContent-Container"gt; lt;div class="PostContent-Header"gt; @Model.CreatedOn lt;/divgt; lt;div class="PostContent-Text"gt; @Html.Raw(Model.PostContent) lt;/divgt; lt;div class="PostContent-Footer"gt; @if (User.Identity.Name == Model.AuthorName || User.IsInRole("Admin")) { lt;a class="ClassicButton Button-EditPost" data-target="#modalEditPost" onclick="toggleModalPost()"gt; Edit lt;/agt; } lt;/divgt; lt;/divgt; lt;/divgt; foreach (var reply in Model.Replies) { lt;div class="row PostIndex-ReplyContent"gt; lt;div ReplyContent-Container"gt; lt;div class="PostContent-Header"gt; @reply.CreatedOn lt;/divgt; lt;div class="PostContent-Text"gt; @Html.Raw(reply.ReplyContent) lt;/divgt; lt;div class="PostContent-Footer"gt; @if (User.Identity.Name == Model.AuthorName || User.IsInRole("Admin")) //added { lt;a class="ClassicButton Button-EditPost" data-target="#modalEditPost" onclick="toggleModalPostReply()"gt; Edit lt;/agt; } lt;/divgt; lt;/divgt; lt;/divgt; //modal for edit PostReply lt;div class="modal fade" id="modalEditPostReply" tabindex="-1" role="dialog" aria-labelledby="modalEditPostReply" aria-hidden="true"gt; lt;div class="modal-dialog modal-dialog-centered" role="document"gt; lt;div class="modal-content"gt; lt;div class="EditPostFormHeader"gt; Edit Post Reply lt;/divgt; lt;form id="EditPostForm1" class="EditPostForm" asp-controller="Post" asp-action="EditReply" method="post"gt; lt;input asp-for="@reply.Id" type="hidden" /gt; lt;div class="EditPostTextarea"gt; lt;textarea rows="10" asp-for="@reply.ReplyContent" requiredgt;lt;/textareagt; lt;label asp-for="@reply.ReplyContent"gt;lt;/labelgt; lt;span asp-validation-for="@reply.ReplyContent" class="text-danger"gt;lt;/spangt; lt;/divgt; lt;div class="CreatePostButtonRow"gt; lt;input type="submit" value="edit reply" /gt; lt;/divgt; lt;/formgt; lt;/divgt; lt;/divgt; lt;/divgt; lt;/divgt;
PostController
Часть, ответственная за принятие этого:
[Authorize] [HttpPost] public async Tasklt;IActionResultgt; EditReply(PostReplyModel model) { var reply = _postService.GetReplyById(model.Id); await _postService.EditPostReplyContent(reply.Id, model.ReplyContent); return RedirectToAction("Index", new { id = model.PostId }); }
Не могли бы вы, пожалуйста, помочь? Есть ли способ вывести модальное из цикла и все еще быть в состоянии сделать это? Заранее спасибо.
Комментарии:
1. @marc_s Спасибо, что отредактировали мой вопрос. Это помогло мне понять, как сделать это лучше в следующий раз.
2. Есть какие-нибудь предложения?
3. Привет @Oggie, в моем ответе ниже были описаны два способа. Пожалуйста, проверьте мое подробное объяснение.
Ответ №1:
Первый способ с помощью цикла
Представление (Index.cshtml):
1.Вы не разделяете то, что есть toggleModalPost
, и toggleModalPostReply
функцию js. На самом деле нет необходимости использовать какую-либо функцию js для создания модального всплывающего окна. Просто используйте атрибут начальной загрузки по умолчанию data-toggle="modal"
.
2.Ваш модальный идентификатор есть modalEditPostReply
, но значение data-target
в якоре ему не соответствует. Кроме того, все модальные должны иметь уникальный идентификатор. Вам нужно добавить индекс, чтобы сделать его уникальным.
@model PostIndexModel @{ int i = 0;} lt;!--add here --gt; lt;div class="container"gt; lt;div class="row PostIndex-PostContent"gt; lt;div class="PostContent-Container"gt; lt;div class="PostContent-Header"gt; @Model.CreatedOn lt;/divgt; lt;div class="PostContent-Text"gt; @Html.Raw(Model.PostContent) lt;/divgt; lt;div class="PostContent-Footer"gt; lt;!--Not sure which modal does this edit button launch--gt; lt;a class="ClassicButton Button-EditPost" data-toggle="modal" data-target="#modalEditPost_@i"gt; EditPost lt;/agt; lt;/divgt; lt;/divgt; lt;/divgt; @foreach (var reply in Model.Replies) { lt;div class="row PostIndex-ReplyContent"gt; lt;div ReplyContent-Container"gt; lt;div class="PostContent-Header"gt; @reply.CreatedOn lt;/divgt; lt;div class="PostContent-Text"gt; @Html.Raw(reply.ReplyContent) lt;/divgt; lt;div class="PostContent-Footer"gt; lt;!--add data-toggle and change data-target --gt; lt;a class="ClassicButton Button-EditPost" data-toggle="modal" data-target="#modalEditPostReply_@i" gt; EditReply lt;/agt; lt;/divgt; lt;/divgt; lt;/divgt; //modal for edit PostReply //modify the id.... lt;div class="modal fade" id="modalEditPostReply_@i" tabindex="-1" role="dialog" aria-labelledby="modalEditPostReply" aria-hidden="true"gt; lt;div class="modal-dialog modal-dialog-centered" role="document"gt; lt;div class="modal-content"gt; lt;div class="EditPostFormHeader"gt; Edit Post Reply lt;/divgt; lt;form id="EditPostForm1" class="EditPostForm" asp-controller="Post" asp-action="EditReply" method="post"gt; lt;input asp-for="@reply.Id" type="hidden" /gt; lt;div class="EditPostTextarea"gt; lt;textarea rows="10" asp-for="@reply.ReplyContent" requiredgt;lt;/textareagt; lt;label asp-for="@reply.ReplyContent"gt;lt;/labelgt; lt;span asp-validation-for="@reply.ReplyContent" class="text-danger"gt;lt;/spangt; lt;/divgt; lt;div class="CreatePostButtonRow"gt; lt;input type="submit" value="edit reply" /gt; lt;/divgt; lt;/formgt; lt;/divgt; lt;/divgt; lt;/divgt; i ; //add here... } lt;/divgt;
Контроллер:
Ваш интерфейс использует asp-for="@reply.PropertyName"
, он будет генерировать name="reply.PropertyName"
, вам нужен конкретный префикс.
[HttpPost] public async Tasklt;IActionResultgt; EditReply([Bind(Prefix ="reply")]PostReplyModel model) { return RedirectToAction("Index"); }
Второй способ — избежать зацикливания
Вы можете использовать частичное представление для повторного использования модального.
Представление (Index.cshtml):
Теперь вы можете использовать функцию js для вызова ajax для загрузки частичного представления, что позволяет избежать зацикливания модального.
@model PostIndexModel lt;div class="container"gt; lt;div class="row PostIndex-PostContent"gt; lt;div class="PostContent-Container"gt; lt;div class="PostContent-Header"gt; @Model.CreatedOn lt;/divgt; lt;div class="PostContent-Text"gt; @Html.Raw(Model.PostContent) lt;/divgt; lt;div class="PostContent-Footer"gt; lt;a class="ClassicButton Button-EditPost" data-target="#modalEditPost"gt; EditPost lt;/agt; lt;/divgt; lt;/divgt; lt;/divgt; @foreach (var reply in Model.Replies) { lt;div class="row PostIndex-ReplyContent"gt; lt;div ReplyContent-Container"gt; lt;div class="PostContent-Header"gt; @reply.CreatedOn lt;/divgt; lt;div class="PostContent-Text"gt; @Html.Raw(reply.ReplyContent) lt;/divgt; lt;div class="PostContent-Footer"gt; lt;a class="ClassicButton Button-EditPost" data-target="#modalEditPostReply" onclick="toggleModalPostReply('@reply.Id')"gt; EditReply lt;/agt; lt;/divgt; lt;/divgt; lt;/divgt; lt;div id="loadModal"gt; lt;!--load the modal--gt; lt;/divgt; } lt;/divgt; @section Scripts { lt;scriptgt; function toggleModalPostReply(id) { $.ajax({ type: "Get", url: "/Post/LoadPartial?id=" id, success: function (data) { $("#loadModal").html(data); $('#modalEditPostReply').modal('show') } }) } lt;/scriptgt; }
Частичное представление (_Partial.cshtml находится в Представлениях/Общей папке):
@model PostReplyModel lt;div class="modal fade" id="modalEditPostReply" tabindex="-1" role="dialog" aria-labelledby="modalEditPostReply" aria-hidden="true"gt; lt;div class="modal-dialog modal-dialog-centered" role="document"gt; lt;div class="modal-content"gt; lt;div class="EditPostFormHeader"gt; Edit Post Reply lt;/divgt; lt;form id="EditPostForm1" class="EditPostForm" asp-controller="Post" asp-action="EditReply" method="post"gt; lt;input asp-for="Id" type="hidden" /gt; lt;div class="EditPostTextarea"gt; lt;textarea rows="10" asp-for="ReplyContent" requiredgt;lt;/textareagt; lt;label asp-for="ReplyContent"gt;lt;/labelgt; lt;span asp-validation-for="ReplyContent" class="text-danger"gt;lt;/spangt; lt;/divgt; lt;div class="CreatePostButtonRow"gt; lt;input type="submit" value="edit reply" /gt; lt;/divgt; lt;/formgt; lt;/divgt; lt;/divgt; lt;/divgt;
Контроллер:
public IActionResult LoadPartial(int id) { var data = _context.Replies.Where(i =gt; i.Id == id).FirstOrDefault(); return PartialView("_Partial", data); } [HttpPost] public async Tasklt;IActionResultgt; EditReply(PostReplyModel model) { return RedirectToAction("Index"); }
Комментарии:
1. Большое спасибо, Рена. Я пытался сделать это вторым способом, но у меня возникли проблемы с частичным представлением.
2. В чем проблема?
3. Возможно, вы меня неправильно поняли. Моя вина в том, что я так отреагировал. Ты действительно помог мне, и мне удалось это сделать. У меня были проблемы, когда я пытался сделать это сам, прежде чем вы отправили ответ. Я застрял с вызовом частичного представления с помощью
@Html.Action()
и понял, что оно больше недоступно в .net core. Ваш способ использования js и ajax сделал свое дело. Снова Tnx.4. Хорошо. Рад вам помочь. 🙂