ASP .NET Core 5 Razor Pages: how to properly use Partial View and validate it's model state?

Viewed 5123

I'm using ASP .NET Core 5 Razor Pages.

My goal is to has a set of Partial Views (for reusability purpose) that I can use on several pages. Each Partial View has a form with its own custom post event handler (it will be processed by a code-behind of a pages that will contain this Partial View).

N.B. Some pages can contain two or even more different Partial Views! And I need that Partial View models to be validated independently of each other (in two separate custom event handlers).

Here is simplified code that I use for today. Partial View model (contains some data for a user):

public partial class User
{
    [Required]
    public string Name { get; set; }
    [Required]
    public string Surname { get; set; }
}    

public class UserModel : PageModel
{
    [BindProperty]
    public User user { get; set; }
    [TempData]
    public string StatusMessage { get; set; }
    public UserModel()
    {
        user = new User();
    }
}

_UserPartial.cshtml (displays that user data):

@model UserModel

<div class="row text-warning">
    <div class="col-md-4">
        <form method="post" asp-page-handler="UserEdited">
            <div asp-validation-summary="ModelOnly"></div>
            <div class="form-group">
                <label asp-for="user.Surname" class="control-label"></label>
                <input asp-for="user.Surname" class="form-control" />
                <span asp-validation-for="user.Surname" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="user.Name" class="control-label"></label>
                <input asp-for="user.Name" class="form-control" />
                <span asp-validation-for="user.Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Save user data" />
            </div>
        </form>
    </div>
</div>

Index.cshtml (main page that contains Partial View):

@page
@model IndexModel
@{
    ViewData["Title"] = "Main page";
}    

@if (!String.IsNullOrWhiteSpace(@Model.StatusMessage))
{
    <div class="text-center">
        <h4 class="text-warning">@Model.StatusMessage</h4>
    </div>
}    

<div class="text-center" id="mainView">
    <p>Some text in a main view</p>
    <p>Some <a href="https://docs.microsoft.com/aspnet/core">link</a> in a main view.</p>
</div>

<div class="text-center" id="userPartialView">
    @{await Html.RenderPartialAsync("_UserPartial", IndexModel.userModel);}
</div>
//Some other Partial View (which contains some data for a message)
<div class="text-center" id="userPartialView">
    @{await Html.RenderPartialAsync("_MessagePartial", IndexModel.messageModel);}
</div>

Index.cshtml.cs (code-behind of a main page):

public class IndexModel : PageModel
{
    public static UserModel userModel { get; set; }
    //A model for some other Partial View (which contains some data for a message)
    public static MessageModel messageModel { get; set; }
    [TempData]
    public string StatusMessage { get; set; }        

    public IActionResult OnGet()
    {
        userModel = new UserModel();
        messageModel = new MessageModel();
        return Page();
    }

    public IActionResult OnPostUserEdited()
    {
        if (!userModel.ModelState.IsValid)
        {
            return Page();
        }

        StatusMessage = "User data was saved!";
        return RedirectToPage();
    }
}

Problem is that userModel.ModelState is always valid even if Name and Surname are empty: Looks like UserModel is not validaiting at all Looks like UserModel is not validaiting at all.

And I have a strong feeling that I'm using Partial Views tha wrong way (not the way they were supposed to be used).

So what's wrong with my code? How to properly use Partial View and validate it's model state? Any help is appreciated.

1 Answers

You don't need to have a Page Model for the partial view. Just add it as a Razor View.

enter image description here

Index.cshtml.cs

[BindProperty]
public User userModel { get; set; }

[BindProperty]
public Message messageModel { get; set; }

[TempData]
public string StatusMessage { get; set; }

public void OnGet()
{
    userModel = new User();
}

public IActionResult OnPostUserEdited()
{
    ModelState.Clear();
    if (!TryValidateModel(userModel))
    {
        return Page();
    }

    StatusMessage = "User data was saved!";
    return RedirectToPage();
}

public IActionResult OnPostMessageEdited()
{
    ModelState.Clear();
    if (!TryValidateModel(messageModel))
    {
        return Page();
    }

    StatusMessage = "Message data was saved!";
    return RedirectToPage();
}

Index.cshtml:

<div class="text-center" id="userPartialView">
    @{await Html.RenderPartialAsync("_UserPartial", Model.userModel);}
</div>

<div class="text-center" id="messagePartialView">
    @{await Html.RenderPartialAsync("_MessagePartial", Model.messageModel);}
</div>

enter image description here

Related