Search code examples
asp.net-coreasp.net-core-mvcpartial-views

How to display Partial view Model errors when partial view is in the view?


I am working on the Asp.net Core 2.0 project and have a partial view that is shown in the index view. This partial view have a Model with some validation errors.

You can continue to see my Model,Partial view,controller and ...

LoginViewModel

public class LoginViewModel
{
    [Display(Name = "UserName")]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Please Enter UserName")]
    public string UserName { get; set; }

    [Display(Name = "Password")]
    [Required(AllowEmptyStrings = false, ErrorMessage = "Please Enter Password")]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [Display(Name = "Remember Me")]
    public bool RememberMe { get; set; }
}

I have used LoginViewModel as model in _loginpartialView. also there are asp-validation-for to show validation error after each input

_loginpartialView.cshtml

@model partialView.Models.LoginViewModel

    <div id="login">
        <span class="header-lastnews">Login</span>
        <div class="hr"></div>

        <form asp-controller="Account" asp-action="Login" method="post">


            <div class="form-group">
                <label asp-for="UserName" class="col-sm-4 control-label"></label>
                <div class="col-sm-8">
                    <input asp-for="UserName" class="form-control" />
                    <span asp-validation-for="UserName" class="text-danger"></span>
                </div>
            </div>


            <div class="form-group">
                <label asp-for="Password" class="col-sm-4 control-label"></label>
                <div class="col-sm-8">
                    <input asp-for="Password" class="form-control" />
                    <span asp-validation-for="Password" class="text-danger"></span>
                </div>
            </div>

            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <div class="checkbox">
                        <label asp-for="RememberMe">
                            <input asp-for="RememberMe" />
                            @Html.DisplayNameFor(m => m.RememberMe)
                        </label>
                    </div>
                </div>
            </div>

            <div class="row" style="width: 100%">
                <div class="form-group pull-left ">
                    <button type="submit" class="btn btn-success">Enter</button>
                </div>
            </div>
        </form>
    </div>

I have used @Html.Partial to render and show partial view in index Be careful that the index view is inside the HomeController

Index.cshtml

@{
     ViewData["Title"] = "Home Page";
}

@Html.Partial("_loginpartialView")

And at the end this is my AccountController

AccountController

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            //Success Login
            //do Something
        }
        else
        {
            //if ModelState is invalid
            return PartialView("_loginpartialView", model);
        }

        //if UserName Or Password is incorrect
        return PartialView("_loginpartialView", model);
    }

But the problem is that when I click on the submit button without entering the inputs value, a new page opens and partial view and Model errors show on new page. How can i show model errors in partial view in the same view not a new page?


Solution

  • This is a standard form submission tag, which sends POST request and returns new page as expected response:

    <form asp-controller="Account" asp-action="Login" method="post">
    

    Since you want to return partial view into same page with validation errors, you must use AJAX-based form. You can convert standard form submit like above into AJAX-based form which returns partial view at the same main view, as in example below:

    <form id="partialform" asp-controller="Account" asp-action="Login" data-ajax="true" data-ajax-update="#partialform" data-ajax-mode="replace">
        <!-- form inner elements here -->
    </form>
    

    The most important things you should remember:

    1. data-ajax="true" must be exist to ensure form accepts AJAX data.

    2. Setting id attribute and provide that ID value to data-ajax-update property so that the jQuery selector behind AJAX callback recognizes it.

    3. data-ajax-mode="replace" set to replace previous form element together with its inner elements after AJAX success result to response from server.

    Note: The form inner element replacement with data-ajax-mode="replace" is done by jquery.unobtrusive-ajax.js script which runs in background.