4

I've just faced a really strange behavior of Razor engine regarding adding unobtrusive validation attributes to inputs in forms. In some cases attributes are not added.

So, I have two similar forms on the same page with similar input elements. They must be submitted to different url's. From model side, I have a few DataAnnotations Attributes, applied to properties to have a client-side validation.

Here is my a bit simplified code of ViewModel:

public class ApplicantPersonalInfo
    {
        [Required]
        [Display(Name = "First Name")]
        [StringLength(20, MinimumLength = 2)]
        [RegularExpression(@"^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘'`-]+$", ErrorMessage = "First Name is in incorrect format")]
        public string FirstName { get; set; }
}

Now I want to create two forms. For every of them action url can differ dynamically (I submit them using ajaxSubmit from jQuery Form Plugin), that's why I decided not to use Html.BeginForm helper method, instead creating them with simple <form> tag. So my code is:

<form id="form1">
    @Html.TextBoxFor(m => Model.FirstName, new { id = "firstName1" })
</form>
<form id="form2">
    @Html.TextBoxFor(m => Model.FirstName, new { id = "firstName2" })
</form>

And the most interesting is the resulting html code:

<form id="form1">
    <input data-val="true" data-val-length="The field First Name must be a string with a minimum length of 2 and a maximum length of 20." data-val-length-max="20" data-val-length-min="2" data-val-regex="First Name is in incorrect format" data-val-regex-pattern="^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘&#39;`-]+$" data-val-required="The First Name field is required." id="firstName1" name="FirstName" type="text" value=""/>
</form>
<form id="form2">
    <input id="firstName2" name="FirstName" type="text" value=""/>
</form>

See? All those validation attributes are not applied to the second input! BUT if the form is generated using Html.BeginForm, like this:

@using (Html.BeginForm("NotExistingController", "NotExisitngAtion", FormMethod.Post, new { id = "form1" }))
{
    @Html.TextBoxFor(m => Model.HomeOwner.FirstName, new { id = "firstName1" })
}
<form id="form2">
    @Html.TextBoxFor(m => Model.HomeOwner.FirstName, new { id = "firstName2" })
</form>

the resulting html code is with attributes in both inputs:

<form action="/NotExisitngAtion/NotExistingController" id="form1" method="post">
        <input data-val="true" data-val-length="The field First Name must be a string with a minimum length of 2 and a maximum length of 20." data-val-length-max="20" data-val-length-min="2" data-val-regex="First Name is in incorrect format" data-val-regex-pattern="^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘&#39;`-]+$" data-val-required="The First Name field is required." id="firstName1" name="FirstName" type="text" value="" />
</form>
<form id="form2">
        <input data-val="true" data-val-length="The field First Name must be a string with a minimum length of 2 and a maximum length of 20." data-val-length-max="20" data-val-length-min="2" data-val-regex="First Name is in incorrect format" data-val-regex-pattern="^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘&#39;`-]+$" data-val-required="The First Name field is required." id="firstName2" name="FirstName" type="text" value="" />
</form>

I'm really confused by this behavior. And I've tried - you can add as much forms as you want using Html.BeginForm - every of them will have set of validation attributes; but if you add >1 form using simple <form> tag, starting from the second one attributes are missing.

So am I missing something or it's a bug in Razor engine?

  • 1
    Not directly related, but [this answer](http://stackoverflow.com/questions/29047930/html-checkboxfor-generates-client-side-validation-attributes-while-html-check/29048385#29048385) explains the behavior. But why are you generating 2 forms with 2 sets of controls - you can only post one a a time? And if your using ajax, then just have one form with 2 submit buttons and handle the buttons event to change the url to post to based on which button was clicked. –  Oct 01 '16 at 22:12
  • @Stephen Muecke thanks for your link, it explains why it doesn't work in case of 2 simple elements. But still interesting, why all forms from HtmlHelper have validation attributes. – Kozak Vasyl Oct 02 '16 at 01:01
  • @Stephen Muecke About your question - to be honest I've just found I don't post second form at all, just use it as a container with validation. I have a form with a few blocks of personal info (like block of name/lastname/birthdate, block of address fields, etc.). And every block can be edited in modal window (with validation). In case of changes are valid, data from modal is copied to corresponding block in main form (just locally, not to database). This way can be edited a few separate blocks. Afterwards you click button in main from and submit all changes together to database. – Kozak Vasyl Oct 02 '16 at 01:02
  • Its to do with the form context (specifically the `FormContext formContext = ViewContext.GetFormContextForClientValidation();` line of code and the `if` blocks that follow it in the [GetUnobtrusiveValidationAttributes()](http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/HtmlHelper.cs) method –  Oct 02 '16 at 01:07
  • Not sure I fully understand your 2nd comment, but it sound like your taking the wrong approach and you certainly should not be generating multiple for controls for the same element - It sounds like you might be wanting some kind of wizard where your can display and validate sections of a form (refer [this answer](http://stackoverflow.com/questions/25643394/mvc-force-jquery-validation-on-group-of-elements/25645097#25645097) for an example) –  Oct 02 '16 at 01:13
  • @Stephen Muecke Thanks for your example, but my case is a bit different, 'cause there must be a modal with the same set of fields, like [here](http://formvalidation.io/examples/loading-saving-data-modal/) (but more complicated, 'cause all set of data must be submitted in the end). About generating multiple for controls for the same element - I thought most important to have different Ids to make html page valid, but Names can be same, just in different forms, like [here](http://stackoverflow.com/questions/2906793/is-it-valid-to-have-two-input-elements-with-the-same-name). Or not? – Kozak Vasyl Oct 02 '16 at 01:41
  • The link you gave is for a list of items, in which case your implementation makes no sense because you need only one form - either you generate form controls for each item in the collection inside a single form (using a `for` loop or using a custom `EditorTemplate`) so you can edit and post back everything in one action, or you generate a the table with text only and a single dialog form that gets populated with the data from the associated row, and you use ajax to post back and update one row at a time. –  Oct 02 '16 at 01:56
  • @Stephen Muecke I meant that just as example of editing in modal, but anyway, as you mentioned above, it's possible to edit in modal, but how about validation? To validate somethings, it must be in a form. So I can either put it to separate form or put all modal to the main form. But in the last case I'll have to implement some sophisticated technique of data copying from input to input (now I just simply copy to input with the same name) – Kozak Vasyl Oct 02 '16 at 02:23
  • But what is the 'other' form for? If you want to edit all items in the collection in one action then you generate form controls for each property of each item in side one form so a modal form is not required (and would be rather pointless), or you do it as per the link you gave (its just a table with text and you update the modal's form controls with the values of the table cells when the edit button is clicked, then update one row at a time using ajax. –  Oct 02 '16 at 02:27
  • @Stephen Muecke You are right, but validation means everything here. Changes must be validated after the Edit button in modal is clicked. And if they are not valid, modal don't close and validation message is displayed in it. That's why modal has it's own form inside. – Kozak Vasyl Oct 02 '16 at 02:39
  • You have a classic [X-Y problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). You think your using the right solution to solve a problem but your not understanding the correct approach. If you have a modal form in you view for editing one row, then you only have one form (there is no need for 'another' form, so there is no problem - if you think you need a 2nd form, then your not taking the correct approach) –  Oct 02 '16 at 02:45
  • For reference: https://github.com/aspnet/AspNetCore/issues/6584 – shlgug Jan 13 '19 at 12:27

0 Answers0