locked
Form is regenerating in case of validation error. RRS feed

  • Question

  • User-826336654 posted

    Hi All,

    I have a created a new ASP.NET MVC 5 application. Then I create a View. When I run the application and click on Save Record Button. In case of the validation error(s), the full view is regenerated and validation message as shown below. Note: It works correctly if there is NO Validation Error and I am using AJAX form.

    Can somebody tell me, where is the problem?

    Controller:

    using JIWebPictureDemo.Models;
    using JIWebPictureDemo.ViewModels.Students;
    using System.Collections.Generic;
    using System.Web;
    using System.Web.Mvc;
    
    namespace JIWebPictureDemo.Controllers
    {
        public class HomeController : Controller
        {
            // GET: Home
            public ActionResult Index()
            {
                StudentViewModel svm = new StudentViewModel();
                Student student = new Student();
                student.StudentId = svm.GenerateStudentId();
                return View(student);
            }
    
            [HttpPost, ValidateAntiForgeryToken]
            public ActionResult Index(Student student, HttpPostedFileBase file)
            {
    
                if (ModelState.IsValid)
                {
                    if (file != null && file.ContentLength > 0)
                    {
                        student.Photo = new byte[file.ContentLength];
                        file.InputStream.Read(student.Photo, 0, file.ContentLength);
                    }
    
                    StudentViewModel svm = new StudentViewModel();
                    svm.InsertStudentInfo(student);
    
                    ViewBag.Message = "Student Details are saved successfully.";
    
                    return PartialView("~/Views/Shared/PartialPages/Message.cshtml");
                }
    
                return View(student);
            }
        }
    }

    View:

    @model JIWebPictureDemo.Models.Student
    
    @{
        ViewBag.Title = "Index";
    }
    
    <script type="text/javascript">
        function OnBegin() {
            $('#progress').show();
        }
    
        function OnSuccess(response) {
            $('#progress').hide();
        }
    
        function OnFailure(response) {
            $('#progress').hide();
        }
    </script>
    
    
    @using (Ajax.BeginForm("Index", "Home", FormMethod.Post, new AjaxOptions
    {
        OnSuccess = "OnSuccess",
        OnFailure = "OnFailure",
        OnBegin="OnBegin",
        UpdateTargetId = "successmsg",
        LoadingElementId = "progress"
    }, new { enctype = "multipart/form-data" }))
    {
        @Html.AntiForgeryToken()
    
        <div class="form">
    
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="row">
                <div class="col-md-2">
                    <div class="row">
                        <div class="col-md-12">
                            <br /> <br />
                            <a href="" onclick="ChangePicture(); return false">
                                <img id="image" src="~/Images/not-available.jpg" alt="" class="img-rounded img-border" width="160" height="160" />
                            </a>
                            <br />
                            <input accept="image/*" type="file" id="upload" name="file" onchange="ReadURL(this);" style="visibility: hidden;" />
                            @*<a href="" onclick="changePicture(); return false">Change Picture</a>*@
                        </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12">
                            <ul class="list-group">
                                <li class="list-group-item list-group-item-success">Result Info</li>
                                <li class="list-group-item list-group-item-success">Student Fees</li>
                                <li class="list-group-item list-group-item-success">Previous Qaulifications</li>
                            </ul>
                        </div>
                    </div>
                </div>
    
                <div class="col-md-10">
                    <div class="page-header">
                        <h3>Basic Information</h3>
                    </div>
    
                    <div class="row">
                        <div class="col-md-12">
                            <div class="form-group">
                                @Html.LabelFor(model => model.StudentId, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.StudentId, new { htmlAttributes = new { @class = "form-control", @readonly= "readonly", @style = "max-width: 15%" } })
                                @Html.ValidationMessageFor(model => model.StudentId, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.FullName, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.FullName, new { htmlAttributes = new { @class = "form-control", @placeholder = "Enter Full Name here" } })
                                @Html.ValidationMessageFor(model => model.FullName, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.Mobile, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.Mobile, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Mobile, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.Telephone, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.Telephone, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Telephone, "", new { @class = "text-danger" })
                            </div>
                        </div>
                    </div>
    
                    <div class="page-header">
                        <h3>Address</h3>
                    </div>
    
                    <div class="row">
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.Address1, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.Address1, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Address1, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.Address2, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.Address2, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.Address2, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.City, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.City, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.City, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.County, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.County, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.County, "", new { @class = "text-danger" })
                            </div>
                        </div>
    
                        <div class="col-md-6">
                            <div class="form-group">
                                @Html.LabelFor(model => model.PostCode, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.PostCode, new { htmlAttributes = new { @class = "form-control" } })
                                @Html.ValidationMessageFor(model => model.PostCode, "", new { @class = "text-danger" })
                            </div>
                        </div>
                    </div>
    
                    <div class="row">
                        <div class="col-md-12">
                            <div class="form-group">
                                @Html.LabelFor(model => model.Notes, htmlAttributes: new { @class = "control-label" })
                                @Html.EditorFor(model => model.Notes, new { htmlAttributes = new { @class = "form-control", @style = "max-width: 82%; height: 150px;" } })
                                @Html.ValidationMessageFor(model => model.Notes, "", new { @class = "text-danger" })
                            </div>
                        </div>
                    </div>
    
                    <div class="row">
                        <div class="form-group">
                            <div class="col-md-10">
                                <input type="submit" value="Save Record" class="btn btn-primary" />
                                @Html.ActionLink("Back to List", "StudentList", "Home", null, new { @class = "btn btn-default" })
                            </div>
                        </div>
                    </div>
    
                </div>
            </div>
        </div>
    }
    
    <br />
    <div id="successmsg"></div>
    
    <div id="progress" class="modal">
        <div class="center">
            <img src="~/Images/loader.gif" />
        </div>
    </div>

    Model:

    using System.ComponentModel.DataAnnotations;
    
    namespace JIWebPictureDemo.Models
    {
        public class Student
        {
            public byte[] Photo { get; set; }
    
            [Display(Name = "Student Id:")]
            public int StudentId { get; set; }
    
            [Display(Name = "Full Name:")]
            [Required(ErrorMessage = "Full Name is required.")]
            public string FullName { get; set; }
    
            [Display(Name = "Email Address:")]
            [Required(ErrorMessage = "Email Address is required.")]
            public string Email { get; set; }
    
            [Display(Name = "Mobile:")]
            public string Mobile { get; set; }
    
            [Display(Name = "Telephone:")]
            public string Telephone { get; set; }
    
            [Display(Name = "Address 1:")]
            public string Address1 { get; set; }
    
            [Display(Name = "Address 2:")]
            public string Address2 { get; set; }
    
            [Display(Name = "City:")]
            [UIHint("CityComboBox")]
            public int City { get; set; }
    
            [Display(Name = "County:")]
            [UIHint("CountyComboBox")]
            public int County { get; set; }
    
            [Display(Name = "Post Code:")]
            public string PostCode { get; set; }
    
            [Display(Name = "Notes:")]
            [DataType(DataType.MultilineText)]
            public string Notes { get; set; }
        }
    }

    Layout:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>@ViewBag.Title - Star-Bank School</title>
        <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
        <link href="~/Content/bootstrap.css" rel="stylesheet" type="text/css" />
        <script src="~/Scripts/modernizr-2.8.3.js"></script>
    </head>
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    @Html.ActionLink("Star-Bank School", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav"></ul>
                </div>
            </div>
        </div>
    
        <div class="container body-content">
            @RenderBody()
            <hr />
            <footer>
                <p>&copy; @DateTime.Now.Year - Star-Bank School</p>
            </footer>
        </div>
    
        <script src="~/Scripts/jquery-3.3.1.js"></script>
        <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
        <script src="~/Scripts/bootstrap.js"></script>
        <script src="~/Scripts/Site.js"></script>
    </body>
    </html>

    Kind Regards,

    Sunday, December 23, 2018 5:58 PM

Answers

  • User-474980206 posted

    the ajax form is pretty simple. if the server responds with html, it places in the UpdateTargetId div.  your action should always return the html that should be rendered there. generally you want to return a partial view because the page already has the layout html.

    there are two approaches to using the ajax form.

    1) like yours there is a separate div to display success / error message. in this case you never return the form data because its already on the page.  the form element validation is only for client side validation, as the server side one will not be return on post back, just the success or error message.

    in you case, when there is a model error, you should return a partial view that just a validation summary, not the complete form.

    2) the more common approach used by most MS example, is the form is in the partial, and post back always re-renders the form. 

    // main razor page
    ...
    
    <div id="myTargetId">
      @Html.Partial("theAjaxForm", model)
    </div>
    
    
    




     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 24, 2018 12:20 AM
  • User-826336654 posted

    <g class="gr_ gr_15 gr-alert gr_gramm gr_inline_cards gr_run_anim Punctuation only-ins replaceWithoutSep" id="15" data-gr-id="15">Thanks</g> <g class="gr_ gr_14 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="14" data-gr-id="14">bruce</g>, it is working as per your answer.

    But I have also fixed the problem by using "unobtrusive Validation". I have changed Layout slightly. The blue lines <g class="gr_ gr_16 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar multiReplace" id="16" data-gr-id="16">needs</g> to add by adding References.

    Note: Add References first from Nuget.

        <script src="~/Scripts/jquery.validate.js"></script>
        <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

    The complete new code of layout is below. 

    Layout:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>@ViewBag.Title - Star-Bank School</title>
        <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
        <link href="~/Content/bootstrap.css" rel="stylesheet" type="text/css" />
        <script src="~/Scripts/modernizr-2.8.3.js"></script>
    </head>
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    @Html.ActionLink("Star-Bank School", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav"></ul>
                </div>
            </div>
        </div>
    
        <div class="container body-content">
            @RenderBody()
            <hr />
            <footer>
                <p>&copy; @DateTime.Now.Year - Star-Bank School</p>
            </footer>
        </div>
    
        <script src="~/Scripts/jquery-3.3.1.js"></script>
        <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
        <script src="~/Scripts/jquery.validate.js"></script>
        <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
        <script src="~/Scripts/bootstrap.js"></script>
        <script src="~/Scripts/Site.js"></script>
    </body>
    </html>

    Regards,

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 24, 2018 11:00 AM

All replies

  • User-474980206 posted

    the ajax form is pretty simple. if the server responds with html, it places in the UpdateTargetId div.  your action should always return the html that should be rendered there. generally you want to return a partial view because the page already has the layout html.

    there are two approaches to using the ajax form.

    1) like yours there is a separate div to display success / error message. in this case you never return the form data because its already on the page.  the form element validation is only for client side validation, as the server side one will not be return on post back, just the success or error message.

    in you case, when there is a model error, you should return a partial view that just a validation summary, not the complete form.

    2) the more common approach used by most MS example, is the form is in the partial, and post back always re-renders the form. 

    // main razor page
    ...
    
    <div id="myTargetId">
      @Html.Partial("theAjaxForm", model)
    </div>
    
    
    




     

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 24, 2018 12:20 AM
  • User-826336654 posted

    <g class="gr_ gr_15 gr-alert gr_gramm gr_inline_cards gr_run_anim Punctuation only-ins replaceWithoutSep" id="15" data-gr-id="15">Thanks</g> <g class="gr_ gr_14 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling ins-del multiReplace" id="14" data-gr-id="14">bruce</g>, it is working as per your answer.

    But I have also fixed the problem by using "unobtrusive Validation". I have changed Layout slightly. The blue lines <g class="gr_ gr_16 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar multiReplace" id="16" data-gr-id="16">needs</g> to add by adding References.

    Note: Add References first from Nuget.

        <script src="~/Scripts/jquery.validate.js"></script>
        <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

    The complete new code of layout is below. 

    Layout:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>@ViewBag.Title - Star-Bank School</title>
        <link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
        <link href="~/Content/bootstrap.css" rel="stylesheet" type="text/css" />
        <script src="~/Scripts/modernizr-2.8.3.js"></script>
    </head>
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    @Html.ActionLink("Star-Bank School", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav"></ul>
                </div>
            </div>
        </div>
    
        <div class="container body-content">
            @RenderBody()
            <hr />
            <footer>
                <p>&copy; @DateTime.Now.Year - Star-Bank School</p>
            </footer>
        </div>
    
        <script src="~/Scripts/jquery-3.3.1.js"></script>
        <script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
        <script src="~/Scripts/jquery.validate.js"></script>
        <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
        <script src="~/Scripts/bootstrap.js"></script>
        <script src="~/Scripts/Site.js"></script>
    </body>
    </html>

    Regards,

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, December 24, 2018 11:00 AM