Forms 将ViewComponent与表单一起使用

Forms 将ViewComponent与表单一起使用,forms,asp.net-core,view,razor-pages,view-components,Forms,Asp.net Core,View,Razor Pages,View Components,我正在尝试学习如何在ASP.NET Core Mvc中正确使用ViewComponent,因此我有以下示例:想法是使用电影详细信息渲染视图,其中包含“ReviewViewComponent”,其中包含一个10星电影评级小部件 在ViewComponent的视图中,实际上是一个带有单选按钮的窗体。表单操作名称将传递给ViewComponent(根据用户是否已给出评级,“创建”或“编辑”)。根据收到的操作名称,ViewComponent中的表单将调用ReviewController中的Create或

我正在尝试学习如何在ASP.NET Core Mvc中正确使用ViewComponent,因此我有以下示例:想法是使用电影详细信息渲染视图,其中包含“ReviewViewComponent”,其中包含一个10星电影评级小部件

在ViewComponent的视图中,实际上是一个带有单选按钮的窗体。表单操作名称将传递给ViewComponent(根据用户是否已给出评级,“创建”或“编辑”)。根据收到的操作名称,ViewComponent中的表单将调用ReviewController中的Create或Edit方法

在我到达ReviewController内部的返回调用之前,所有这些都有效。我希望能够在那里返回ViewComponent,并使用ajax在div中以id=“now showing details rating div”详细呈现返回结果。这适用于PartialView(代码在ReviewController编辑方法中注释掉),但似乎不适用于ViewComponents(它只是将ViewComponent视图呈现为一个全新的视图,尽管我在表单上调用ajax的方式与在PartialView中调用ajax的方式相同)

我是否真的误用了ViewComponent的概念?在表单提交后呈现视图的一部分的意义上,仅仅使用PartialViews实际上更好吗

Ajax片段

视图模型:

视图组件

公共类ReviewViewComponent:ViewComponent
{
公共异步任务InvokeAsync(string方法名,ReviewIndexVM review)
{
方法=方法名;
返回视图(审查);
}
}
视图组件默认视图

@model Cinema.DTO.ViewModels.Reviews.ReviewIndexVM
@{
ViewData[“标题”]=“默认值”;
}
@对于(int i=10;i>0;i--)
{
}
视图:

@model Cinema.DTO.ViewModels.Movies.MovieDetailsVM
@使用Microsoft.AspNetCore.Identity
@使用Cinema.Domain.Entities.Identity
@注入SignInManager SignInManager
@注入用户管理器用户管理器
@{
ViewData[“标题”]=“详细信息”;
Layout=“~/Views/Shared/_Layout.cshtml”;
bool first=true;
DateTime currentDate=DateTime.Now;
}
@DisplayFor(model=>model.Title)
  • @DisplayNameFor(model=>model.Title) @DisplayFor(model=>model.Title)
  • @Html.DisplayNameFor(model=>model.Year) @DisplayFor(model=>model.Year)
  • @DisplayNameFor(model=>model.Actors) @DisplayFor(model=>model.Actors)
  • @Html.DisplayNameFor(model=>model.Country) @DisplayFor(model=>model.Country)
  • @DisplayNameFor(model=>model.Directors) @DisplayFor(model=>model.Directors)
  • @DisplayNameFor(model=>model.Duration) @DisplayFor(model=>model.Duration)
  • @*
  • @DisplayNameFor(model=>model.GenreMovies) @DisplayFor(model=>model.GenreMovies)
  • *@
  • @DisplayNameFor(model=>model.VideoLink) @DisplayFor(model=>model.VideoLink)
平均评级@Model.AverageRating
您的评级: @如果(@Model.CurrentUserReview.ReviewId==0) { @wait Component.InvokeAsync(“Review”,new{methodName=“Create”,Review=@Model.CurrentUserReview}) } 其他的 { @wait Component.InvokeAsync(“Review”,new{methodName=“Edit”,Review=@Model.CurrentUserReview}) } @节脚本{ $(文档).ready(函数(){ $('.rating star label')。鼠标悬停(函数(){ $('.rating star').prop('checked',false); }); }); }
查看控制器

[HttpGet]
[授权(角色=角色.用户)]
公共异步任务编辑(int-reviewId)
{
Review Review=wait_unit.Reviews.GetAsync(reviewId);
var authorizationResult=Wait_authorizationService.AuthorizationAsync(用户、审核、操作要求.Update);
if(authorizationResult.successed)
{
ReviewUpdateVM model=review.ToUpdateVM();
返回局部视图(模型);
}
else if(User.Identity.IsAuthenticated)
{
返回新结果();
}
其他的
{
返回新的ChallengeResult();
}           
}
[授权(角色=角色.用户)]
        $.ajax({
            type: "POST",
            url: requestUrl,
            data: form.serialize(),
            success: function (data) {
                $("#" + divZaRezultat).html(data);
            }
        });
    public class MovieDetailsVM
    {
        public string Title { get; set; }
        public int Id { get; set; }
        public int Year { get; set; }
        public string Actors { get; set; }
        public string Country { get; set; }
        public string Directors { get; set; }
        public int Duration { get; set; }
        public string VideoLink { get; set; }
        public string AverageRating { get; set; }
        public string NumberOfReviews { get; set; }
        public ReviewIndexVM CurrentUserReview { get; set; }
    }

    public class ReviewIndexVM
    {
        public int ReviewId { get; set; }
        public int Rating { get; set; }
        public MasterModel User { get; set; }
        public MasterModel Movie { get; set; }
    }
   public class ReviewViewComponent : ViewComponent
   {
       public async Task<IViewComponentResult> InvokeAsync(string methodName, ReviewIndexVM review)
       {
           ViewBag.Method = methodName;
           return View(review);
       }
   }
@model Cinema.DTO.ViewModels.Reviews.ReviewIndexVM
@{
    ViewData["Title"] = "Default";
}

<form asp-controller="Reviews" asp-action="@ViewBag.Method">
    <input asp-for="ReviewId" hidden />
    <input asp-for="Movie.Id" hidden />
    <input asp-for="User.Id" hidden />

    <div class="rating form-group">
        @for (int i = 10; i > 0; i--)
        {
            <input asp-for="Rating" type="radio" value="@i" id="@($"rating-star-{i}")" onclick="this.form.submit();" class="form-control rating-star"><label class="rating-star-label" for="@($"rating-star-{i}")"></label>
        }
    </div>
</form>
@model Cinema.DTO.ViewModels.Movies.MovieDetailsVM
@using Microsoft.AspNetCore.Identity
@using Cinema.Domain.Entities.Identity
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@{
    ViewData["Title"] = "Details";
    Layout = "~/Views/Shared/_Layout.cshtml";
    bool first = true;
    DateTime currentDate = DateTime.Now;
}

<section>
    <div class="container">
        <div class="content-wrap">
            <div class="row">
                <h1 class="h2">@Html.DisplayFor(model => model.Title)</h1>
            </div>
            <div class="row">
                <div class="col-md-4">
                    <img id="movie-poster" class="pull-left" src="~/img/movie-poster.png" />
                </div>
                <div class="col-md-8">
                    <ul class="list-unstyled movie-info">
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Title)</span>
                            @Html.DisplayFor(model => model.Title)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Year)</span>
                            @Html.DisplayFor(model => model.Year)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Actors)</span>
                            @Html.DisplayFor(model => model.Actors)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Country)</span>
                            @Html.DisplayFor(model => model.Country)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Directors)</span>
                            @Html.DisplayFor(model => model.Directors)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Duration)</span>
                            @Html.DisplayFor(model => model.Duration)
                        </li>
                        @*<li>
                                <span>@Html.DisplayNameFor(model => model.GenreMovies)</span>
                                @Html.DisplayFor(model => model.GenreMovies)
                            </li>*@
                        <li>
                            <span>@Html.DisplayNameFor(model => model.VideoLink)</span>
                            @Html.DisplayFor(model => model.VideoLink)
                        </li>
                    </ul>

                    Average rating <span class="badge">@Model.AverageRating</span>
                    <hr />

                    <div asp-authorize asp-roles="@Roles.User">

                        Your rating:

                        <div id="now-showing-details-rating-div">
                            @if (@Model.CurrentUserReview.ReviewId == 0)
                            {
                                @await Component.InvokeAsync("Review", new { methodName = "Create", review = @Model.CurrentUserReview })
                            }
                            else
                            {
                                @await Component.InvokeAsync("Review", new { methodName = "Edit", review = @Model.CurrentUserReview })
                            }
                        </div>
                    </div>

                </div>
            </div>
        </div>

</section>

@section Scripts {
    $(document).ready(function () {
            $('.rating-star-label').mouseover(function () {
                $('.rating-star').prop('checked', false);
            });
    });
    </script>
}
        [HttpGet]
        [Authorize(Roles = Roles.User)]
        public async Task<IActionResult> Edit(int reviewId)
        {

            Review review = await _unit.Reviews.GetAsync(reviewId);

            var authorizationResult = await _authorizationService.AuthorizeAsync(User, review, OperationRequirements.Update);

            if (authorizationResult.Succeeded)
            {
                ReviewUpdateVM model = review.ToUpdateVM();
                return PartialView(model);
            }
            else if (User.Identity.IsAuthenticated)
            {
                return new ForbidResult();
            }
            else
            {
                return new ChallengeResult();
            }           
        }

        [Authorize(Roles = Roles.User)]
        public async Task<IActionResult> Edit(ReviewIndexVM model)
        {
            Review review = model.Create();
            var authorizationResult = await _authorizationService.AuthorizeAsync(User, review, OperationRequirements.Update);

            if (authorizationResult.Succeeded)
            {
                await _unit.Reviews.UpdateAsync(review, model.ReviewId);
                await _unit.SaveAsync();

                return ViewComponent("Review");
                //return Redirect("/Reviews/Details?reviewId=" + review.Id); 
            }
            else if (User.Identity.IsAuthenticated)
            {
                return new ForbidResult();
            }
            else
            {
                return new ChallengeResult();
            }
        }
            }
            else if (User.Identity.IsAuthenticated)
            {
                return new ForbidResult();
            }
            else
            {
                return new ChallengeResult();
            }
        }

@model MovieDetailsVM

@{
    ViewData["Title"] = "Details";
    Layout = "~/Views/Shared/_Layout.cshtml";
    bool first = true;
    DateTime currentDate = DateTime.Now;
}

<section>
    <div class="container">
        <div class="content-wrap">
            <div class="row">
                <h1 class="h2">@Html.DisplayFor(model => model.Title)</h1>
            </div>
            <div class="row">
                <div class="col-md-8">
                    <ul class="list-unstyled movie-info">
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Title)</span>
                            @Html.DisplayFor(model => model.Title)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Year)</span>
                            @Html.DisplayFor(model => model.Year)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Actors)</span>
                            @Html.DisplayFor(model => model.Actors)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Country)</span>
                            @Html.DisplayFor(model => model.Country)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Directors)</span>
                            @Html.DisplayFor(model => model.Directors)
                        </li>
                        <li>
                            <span>@Html.DisplayNameFor(model => model.Duration)</span>
                            @Html.DisplayFor(model => model.Duration)
                        </li>
                        @*<li>
                                <span>@Html.DisplayNameFor(model => model.GenreMovies)</span>
                                @Html.DisplayFor(model => model.GenreMovies)
                            </li>*@
                        <li>
                            <span>@Html.DisplayNameFor(model => model.VideoLink)</span>
                            @Html.DisplayFor(model => model.VideoLink)
                        </li>
                    </ul>

                    Average rating <span class="badge">@Model.AverageRating</span>
                    <hr />

                    <div>

                        Your rating:

                        <div id="now-showing-details-rating-div">
                            @if (@Model.CurrentUserReview == null)
                            {
                                @await Component.InvokeAsync("Review", new { methodName = "Create", review = @Model.CurrentUserReview })
                            }
                            else
                            {
                                @await Component.InvokeAsync("Review", new { methodName = "Edit", review = @Model.CurrentUserReview })
                            }
                        </div>
                    </div>

                </div>
            </div>
        </div>
    </div>
</section>
@section Scripts {
  <script>
    $(document).ready(function () {
        $('.rating-star-label').mouseover(function () {
                $('.rating-star').prop('checked', false);
        });
    });
    function Update() {
        $.ajax({
            type: "POST",
            url: "/Reviews/Edit/@Model.CurrentUserReview.ReviewId",
            data: $("form").serialize(),
            success: function (data) {
                $("#now-showing-details-rating-div").html(data);
            }
        });
    }
  </script>
}
@model ReviewIndexVM
@{
    ViewData["Title"] = "Default";
}

<form asp-controller="Reviews" asp-action="@ViewBag.Method">
    <input asp-for="ReviewId" hidden />
    <input asp-for="Movie.Id" hidden />
    <input asp-for="User.Id" hidden />

    <div class="rating form-group">
        @for (int i = 10; i > 0; i--)
        {
            <input asp-for="Rating" type="radio" value="@i" id="@($"rating-star-{i}")" onclick="Update();" class="form-control rating-star"><label class="rating-star-label" for="@($"rating-star-{i}")"></label>
        }
    </div>
</form>
public class ReviewsController : Controller
{
    private readonly Component2_2Context _context;

    public ReviewsController(Component2_2Context context)
    {
        _context = context;
    }
    // GET: Reviews/Details/5
    public async Task<IActionResult> Details(int? id)
    {
        var reviewIndexVM = await _context.MovieDetailsVM
                                .Include(m => m.CurrentUserReview)
                                .FirstOrDefaultAsync(m => m.Id == id);
        return View(reviewIndexVM);
    }
    // GET: Reviews/Edit/5
    public async Task<IActionResult> Edit(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        var reviewIndexVM = await _context.ReviewIndexVM.FindAsync(id);
        if (reviewIndexVM == null)
        {
            return NotFound();
        }
        return View(reviewIndexVM);
    }

    // POST: Reviews/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Edit(int id, [Bind("ReviewId,Rating")] ReviewIndexVM reviewIndexVM)
    {
        if (id != reviewIndexVM.ReviewId)
        {
            return NotFound();
        }

        if (ModelState.IsValid)
        {
            _context.Update(reviewIndexVM);
            await _context.SaveChangesAsync();
            return ViewComponent("Review");

        }
        return new ChallengeResult();
    }
public class ReviewViewComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(string methodName, ReviewIndexVM review)
    {
        ViewBag.Method = methodName;
        return View(review);
    }
}