55

I have the following MVC 5 Razor HTML helper:

@Html.TextBoxFor(m => m.ShortName, 
  new { @class = "form-control", @placeholder = "short name"})

I need this field to be required (i.e. have a red outline when user navigates out without putting a value inn). In a WebForms HTML 5 I could just say <input type="text" required /> to have this effect. What is the proper syntax to accomplish this in a Razor syntax?

1
  • 10
    Protip: The @ on @placeholder is not needed. It's only needed when the name is a keyword like class. Commented Apr 14, 2014 at 22:58

5 Answers 5

110

You can use the required html attribute if you want:

@Html.TextBoxFor(m => m.ShortName, 
new { @class = "form-control", placeholder = "short name", required="required"})

or you can use the RequiredAttribute class in .Net. With jQuery the RequiredAttribute can Validate on the front end and server side. If you want to go the MVC route, I'd suggest reading Data annotations MVC3 Required attribute.

OR

You can get really advanced:

@{
  // if you aren't using UnobtrusiveValidation, don't pass anything to this constructor
  var attributes = new Dictionary<string, object>(
    Html.GetUnobtrusiveValidationAttributes(ViewData.TemplateInfo.HtmlFieldPrefix));

 attributes.Add("class", "form-control");
 attributes.Add("placeholder", "short name");

  if (ViewData.ModelMetadata.ContainerType
      .GetProperty(ViewData.ModelMetadata.PropertyName)
      .GetCustomAttributes(typeof(RequiredAttribute), true)
      .Select(a => a as RequiredAttribute)
      .Any(a => a != null))
  {
   attributes.Add("required", "required");
  }

  @Html.TextBoxFor(m => m.ShortName, attributes)

}

or if you need it for multiple editor templates:

public static class ViewPageExtensions
{
  public static IDictionary<string, object> GetAttributes(this WebViewPage instance)
  {
    // if you aren't using UnobtrusiveValidation, don't pass anything to this constructor
    var attributes = new Dictionary<string, object>(
      instance.Html.GetUnobtrusiveValidationAttributes(
         instance.ViewData.TemplateInfo.HtmlFieldPrefix));

    if (ViewData.ModelMetadata.ContainerType
      .GetProperty(ViewData.ModelMetadata.PropertyName)
      .GetCustomAttributes(typeof(RequiredAttribute), true)
      .Select(a => a as RequiredAttribute)
      .Any(a => a != null))
    {
      attributes.Add("required", "required");
    }
  }
}

then in your templates:

@{
  // if you aren't using UnobtrusiveValidation, don't pass anything to this constructor
  var attributes = this.GetAttributes();

  attributes.Add("class", "form-control");
  attributes.Add("placeholder", "short name");

  @Html.TextBoxFor(m => m.ShortName, attributes)

}

Update 1 (for Tomas who is unfamilar with ViewData).

What's the difference between ViewData and ViewBag?

Excerpt:

So basically it (ViewBag) replaces magic strings:

ViewData["Foo"]

with magic properties:

ViewBag.Foo
Sign up to request clarification or add additional context in comments.

9 Comments

O', its really nice 1 !
how can we show custom message with required html attribute?
@AashishKumar using the Ask Question button in the upper right to ask a new question.
@ErikPhilips I already asked the question regarding the same. stackoverflow.com/questions/41485898/…
Really effective answer.
|
21

On your model class decorate that property with [Required] attribute. I.e.:

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

5 Comments

Sadly, this adds data-val-required to the element, not required like you'd expect it to.
@humanoidanalog - The expected result would actually be data-val-required, you are working in MVC.
As a web developer I expect required attributes to make my forms validate as "required" under html5. Not as required under a couple MB's of jquery libraries.
I think this should be the right answer working in MVC. Upvoting for more exposure.
[Required] works as expected as long as you are using jqueryValidate and unobtrusive. It wont work right out of the box.
15

A newer way to do this in .NET Core is with TagHelpers.

https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro

Building on these examples (MaxLength, Label), you can extend the existing TagHelper to suit your needs.

RequiredTagHelper.cs

using Microsoft.AspNetCore.Razor.TagHelpers;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.Linq;

namespace ProjectName.TagHelpers
{
    [HtmlTargetElement("input", Attributes = "asp-for")]
    public class RequiredTagHelper : TagHelper
    {
        public override int Order
        {
            get { return int.MaxValue; }
        }

        [HtmlAttributeName("asp-for")]
        public ModelExpression For { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            base.Process(context, output); 

            if (context.AllAttributes["required"] == null)
            {
                var isRequired = For.ModelExplorer.Metadata.ValidatorMetadata.Any(a => a is RequiredAttribute);
                if (isRequired)
                {
                    var requiredAttribute = new TagHelperAttribute("required");
                    output.Attributes.Add(requiredAttribute);
                }
            }
        }
    }
}

You'll then need to add it to be used in your views:

_ViewImports.cshtml

@using ProjectName
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper "*, ProjectName"

Given the following model:

Foo.cs

using System;
using System.ComponentModel.DataAnnotations;

namespace ProjectName.Models
{
    public class Foo
    {
        public int Id { get; set; }

        [Required]
        [Display(Name = "Full Name")]
        public string Name { get; set; }
    }
}

and view (snippet):

New.cshtml

<label asp-for="Name"></label>
<input asp-for="Name"/>

Will result in this HTML:

<label for="Name">Full Name</label>
<input required type="text" data-val="true" data-val-required="The Full Name field is required." id="Name" name="Name" value=""/>

I hope this is helpful to anyone with same question but using .NET Core.

3 Comments

Your entire method body could simply be replaced with return validatorMetadata.Any(vm => vm is RequiredAttribute)
@ErikPhilips you are correct, and for the sake of simplicity I have updated my answer. However, it should be noted that there are potential performance concerns when using LINQ. Particularly when used in rendering the view. YMMV
Nice. I feel like they should build this in as part of ASP.NET Core.
3

I needed the "required" HTML5 atribute, so I did something like this:

<%: Html.TextBoxFor(model => model.Name, new { @required = true })%>

2 Comments

required="true" is incorrect and the input will not be evaluated as required.
Indeed, it was without double quotes. I edited the code.
1

@Erik's answer didn't fly for me.

Following did:

 @Html.TextBoxFor(m => m.ShortName,  new { data_val_required = "You need me" })

plus doing this manually under field I had to add error message container

@Html.ValidationMessageFor(m => m.ShortName, null, new { @class = "field-validation-error", data_valmsg_for = "ShortName" })

Hope this saves you some time.

3 Comments

Inline razor expressions do not end with a semicolon (;) (statements in razor a code block do), so there shouldn't be a semicolon at the end of the razor expression. (Tried to simply edit the line of code but Adam Michalik, for some, reason rejected the edit). See asp.net/web-pages/overview/getting-started/…
should be @Html.TextBoxFor(m => m.ShortName, new { data_val_required = "You need me" }) without the semicolon.
This doesn't answer the question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.