如何编辑 Post 回复 Post 视图而不在单独的视图中执行此操作

How to edit Post Reply on Post View without doing that in a separate View

我正在创建一个论坛。这是一个 ASP.NET Core 3.1 MVC 应用程序。

在 post 索引视图中,顶部有一个 post 标题和内容,post 回复列在下面,带有一个 foreach 循环。我想在同一个视图上实现 EDIT 功能,而不必创建新的单独视图。

我已经为 post 构建了 EDIT 函数。当用户单击 post 上的“编辑”按钮时,会弹出一个 EditPostModal,它就像一个魅力。这对我来说是一项非常容易的任务,因为一个 post 视图只有一个对应的 post.

现在我想对每个回复做类似的事情。我现在遇到的问题是,如果我将用于编辑回复的新模态 window 放在我用于显示回复的同一个 foreach 循环中,我将能够访问所有相关属性以填充模态信息​​,但是弄得一团糟。首先,我认为每个回复都有一个模式有点不合适。此外,现在每个模态实际上都是相同的模态,但具有不同的信息(不同的隐藏 ID 和内容),当我单击提交按钮时,出现 @reply.Id 的空异常,我假设是因为它试图通过从所有模态一次到控制器的信息很混乱。

另一方面,当我将模态 window 放在 foreach 循环之外时,我无法通过模型访问 post 回复信息。或者我根本不知道如何实现。

请在下面找到代码(经过简化,只有相关部分)。

查看型号:

public class PostIndexModel
{
    public int Id { get; set; }
    public string Title { get; set; }
    public DateTime CreatedOn { get; set; }
    public string PostContent { get; set; }

    public IEnumerable<PostReplyModel> Replies { get; set; }
}

public class PostReplyModel
{
    public int Id { get; set; }
    public DateTime CreatedOn { get; set; }
    public string ReplyContent { get; set; }
}

Post 查看 Index.cshtml:

@model WebProjectAircraftForum.Models.Post.PostIndexModel

<div class="container">
<div class="row PostIndex-PostContent">

    <div class="PostContent-Container">
        <div class="PostContent-Header">
            @Model.CreatedOn
        </div>

        <div class="PostContent-Text">
            @Html.Raw(Model.PostContent)
        </div>

        <div class="PostContent-Footer">
            @if (User.Identity.Name == Model.AuthorName || User.IsInRole("Admin"))
            {
                <a class="ClassicButton Button-EditPost" data-target="#modalEditPost" onclick="toggleModalPost()">
                    Edit
                </a>
            }
        </div>
    </div>
</div>

foreach (var reply in Model.Replies)
{
    <div class="row PostIndex-ReplyContent">
        <div ReplyContent-Container">
            <div class="PostContent-Header">
                @reply.CreatedOn
            </div>

            <div class="PostContent-Text">
                @Html.Raw(reply.ReplyContent)
            </div>

            <div class="PostContent-Footer">
                @if (User.Identity.Name == Model.AuthorName || User.IsInRole("Admin")) //added
                {
                    <a class="ClassicButton Button-EditPost" data-target="#modalEditPost" onclick="toggleModalPostReply()">
                        Edit
                    </a>
                }
            </div>
        </div>
    </div>

    //modal for edit PostReply
    <div class="modal fade" id="modalEditPostReply" tabindex="-1" role="dialog" aria-labelledby="modalEditPostReply" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="EditPostFormHeader">
                    Edit Post Reply
                </div>

                <form id="EditPostForm1" class="EditPostForm" asp-controller="Post" asp-action="EditReply" method="post">
                    <input asp-for="@reply.Id" type="hidden" />

                    <div class="EditPostTextarea">
                        <textarea rows="10" asp-for="@reply.ReplyContent" required></textarea>
                        <label asp-for="@reply.ReplyContent"></label>
                        <span asp-validation-for="@reply.ReplyContent" class="text-danger"></span>
                    </div>

                    <div class="CreatePostButtonRow">
                        <input type="submit" value="edit reply" />
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>

负责接受这个的 PostController 部分:

[Authorize]
[HttpPost]
public async Task<IActionResult> EditReply(PostReplyModel model)
{
        var reply = _postService.GetReplyById(model.Id);

        await _postService.EditPostReplyContent(reply.Id, model.ReplyContent);

        return RedirectToAction("Index", new { id = model.PostId });
}

你能帮忙吗?有什么方法可以将模态跳出循环并仍然能够做到这一点?提前致谢。

第一种使用循环的方式

查看(Index.cshtml):

1.You不分享什么是toggleModalPosttoggleModalPostReplyjs函数。实际上不需要使用任何js函数来弹出模态。只需使用默认 bootstrap 属性 data-toggle="modal".

2.Your modal id 是 modalEditPostReply 但锚点中 data-target 的值不匹配。此外,所有模态都应拥有唯一的 ID。您需要添加索引以使其唯一。

@model PostIndexModel

@{ int i = 0;}   <!--add here -->
<div class="container">
    <div class="row PostIndex-PostContent">   
        <div class="PostContent-Container">
            <div class="PostContent-Header">
                @Model.CreatedOn
            </div>
            <div class="PostContent-Text">
                @Html.Raw(Model.PostContent)
            </div>   
            <div class="PostContent-Footer">       <!--Not sure which modal does this edit button launch-->
                <a class="ClassicButton Button-EditPost" data-toggle="modal"  data-target="#modalEditPost_@i">
                    EditPost
                </a>             
            </div>
        </div>
    </div>
    @foreach (var reply in Model.Replies)
    {
    <div class="row PostIndex-ReplyContent">
        <div ReplyContent-Container">
            <div class="PostContent-Header">
                @reply.CreatedOn
            </div> 
            <div class="PostContent-Text">
                @Html.Raw(reply.ReplyContent)
            </div>

            <div class="PostContent-Footer">      <!--add data-toggle and change data-target -->   
                <a class="ClassicButton Button-EditPost" data-toggle="modal" data-target="#modalEditPostReply_@i" >
                    EditReply
                </a>                   
            </div>
        </div>
    </div>    
        //modal for edit PostReply
                              //modify the id....
    <div class="modal fade" id="modalEditPostReply_@i" tabindex="-1" role="dialog" aria-labelledby="modalEditPostReply" aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="EditPostFormHeader">
                    Edit Post Reply
                </div>
                <form id="EditPostForm1" class="EditPostForm" asp-controller="Post" asp-action="EditReply" method="post">
                    <input asp-for="@reply.Id" type="hidden" />

                    <div class="EditPostTextarea">
                        <textarea rows="10" asp-for="@reply.ReplyContent" required></textarea>
                        <label asp-for="@reply.ReplyContent"></label>
                        <span asp-validation-for="@reply.ReplyContent" class="text-danger"></span>
                    </div>

                    <div class="CreatePostButtonRow">
                        <input type="submit" value="edit reply" />
                    </div>
                </form>
            </div>
        </div>
    </div>
        i++;   //add here...
    }
</div>

控制器:

您的前端使用 asp-for="@reply.PropertyName",它将生成 name="reply.PropertyName",您需要指定前缀。

[HttpPost]
public async Task<IActionResult> EditReply([Bind(Prefix ="reply")]PostReplyModel model)
{           
    return RedirectToAction("Index");
}

避免循环的第二种方式

您可以使用局部视图来重用模态。

查看(Index.cshtml):

现在可以使用js函数调用ajax加载局部视图,避免模态循环

@model PostIndexModel    
<div class="container">
    <div class="row PostIndex-PostContent">   
        <div class="PostContent-Container">
            <div class="PostContent-Header">
                @Model.CreatedOn
            </div>
            <div class="PostContent-Text">
                @Html.Raw(Model.PostContent)
            </div>    
            <div class="PostContent-Footer">
                <a class="ClassicButton Button-EditPost" data-target="#modalEditPost">
                    EditPost
                </a>                 
            </div>
        </div>
    </div>
    @foreach (var reply in Model.Replies)
    {
    <div class="row PostIndex-ReplyContent">
        <div ReplyContent-Container">
            <div class="PostContent-Header">
                @reply.CreatedOn
            </div>    
            <div class="PostContent-Text">
                @Html.Raw(reply.ReplyContent)
            </div> 
            <div class="PostContent-Footer">             
                <a class="ClassicButton Button-EditPost" data-target="#modalEditPostReply" 
                                               onclick="toggleModalPostReply('@reply.Id')">   
                    EditReply
                </a>                   
            </div>
        </div>
    </div>
    <div id="loadModal">
              <!--load the modal-->
    </div>
    }
</div>
@section Scripts
{
<script>
    function toggleModalPostReply(id) {
        $.ajax({
            type: "Get",
            url: "/Post/LoadPartial?id="+id,
            success: function (data) {
                $("#loadModal").html(data);
                $('#modalEditPostReply').modal('show')

            }
        })
    }
</script>
}

部分视图(_Partial.cshtml 位于 Views/Shared 文件夹中):

@model PostReplyModel
<div class="modal fade" id="modalEditPostReply" tabindex="-1" role="dialog" aria-labelledby="modalEditPostReply" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="EditPostFormHeader">
                Edit Post Reply
            </div>
            <form id="EditPostForm1" class="EditPostForm" asp-controller="Post" asp-action="EditReply" method="post">
                <input asp-for="Id" type="hidden" />

                <div class="EditPostTextarea">
                    <textarea rows="10" asp-for="ReplyContent" required></textarea>
                    <label asp-for="ReplyContent"></label>
                    <span asp-validation-for="ReplyContent" class="text-danger"></span>
                </div>

                <div class="CreatePostButtonRow">
                    <input type="submit" value="edit reply" />
                </div>
            </form>
        </div>
    </div>
</div>

控制器:

public IActionResult LoadPartial(int id)
{
    var data = _context.Replies.Where(i => i.Id == id).FirstOrDefault();
    return PartialView("_Partial", data);
}


[HttpPost]
public async Task<IActionResult> EditReply(PostReplyModel model)
{           
    return RedirectToAction("Index");
}