简体   繁体   中英

ASP.NET Core + Client Side Validation: No data-val-* attributes are generated if ViewBag and Model has same property name

I realized in ASP.NET Core 2.2 that no data-val-* attributes are generated if ViewBag and Model has the same property name (in my case it is about the propery "Title"). Because of missing data-val-* attributes client side validation does not work.

This is my Model:

public class ActivityModel
{
    public int Id { get; set; }

    [Required]
    public string Title { get; set; }
}

This is my View:

@model ActivityModel

@{ ViewBag.Title = "This is my title"; }  

@using (Html.BeginForm("Create", "Activities"))
{
    @Html.EditorFor(model => model.Title)

    <input type="submit" value="Create" class="btn btn-default" />
}

@section Scripts {
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

The ViewBag.Title property is used in _layout.cshtml to display the current title name.

If I either change the ViewBag or Model property name to something else data-val-* attributes are generated and client side validation works.

From the technical perspective what is causing this behaviour?

While I couldn't figure out the exact reason of why this happening I can suggest you a few workarounds. The obvious one is to assign ViewBag values after rendering inputs

@using (Html.BeginForm("Create", "Activities"))
{
    @Html.EditorFor(model => model.Title)
    <input type="submit" value="Create" class="btn btn-default" />
} 

@{ ViewBag.Title = "This is my title"; }  

Or you can make use of input tag helper since it doesn't suffer from this problem

 <input asp-for="Title" />
 <input type="submit" value="Create" class="btn btn-default" />

Might be interesting

You can disable adding client validation attributes by setting ViewContext.ClientValidationEnabled to false within razor view (this is pretty obvious)

@{
    ViewContext.ClientValidationEnabled = false;
}

If for some reason you need to render more then 1 input for the same property with validation the following code

@Html.EditorFor(model => model.Title)
@Html.EditorFor(model => model.Title)

will render no validation for second input

<input class="text-box single-line" data-val="true" data-val-required="The Title field is required." id="Title" name="Title" type="text" value="Activity">
<input class="text-box single-line" id="Title" name="Title" type="text" value="Activity">

This happens because the renderer tracks rendered properties and prevent adding validation more than once for the same property. The properties are tracked by ViewContext.FormContext so it is possible to control this behavior. Before adding validation attributes the renderer check if property was rendered by calling ViewContext.FormContext.RenderedField(propertyName) and if it renders a property it calls ViewContext.FormContext.RenderedField(propertyName, true) to mark property as rendered. But you can call this method with false like this

@Html.EditorFor(model => model.Title)
@{
    ViewContext.FormContext.RenderedField("Title", false);
}
@Html.EditorFor(model => model.Title)

which gives the following result

<input class="text-box single-line" data-val="true" data-val-required="The Title field is required." id="Title" name="Title" type="text" value="Activity">
<input class="text-box single-line" data-val="true" data-val-required="The Title field is required." id="Title" name="Title" type="text" value="Activity">

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM