Как отредактировать ответ на сообщение в представлении сообщения, не делая этого в отдельном представлении

#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. Хорошо. Рад вам помочь. 🙂