54

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?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Eugene Goldberg
  • 14,286
  • 20
  • 94
  • 167

5 Answers5

109

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
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • O', its really nice 1 ! – Irf May 17 '16 at 19:07
  • how can we show custom message with required html attribute? – Aashish Kumar Jan 05 '17 at 12:40
  • @AashishKumar using the *Ask Question* button in the upper right to ask a new question. – Erik Philips Jan 05 '17 at 15:22
  • @ErikPhilips I already asked the question regarding the same. http://stackoverflow.com/questions/41485898/how-to-add-custom-error-message-with-required-htmlattribute-to-mvc-5-razor-vie – Aashish Kumar Jan 09 '17 at 08:31
  • Really effective answer. – Ananda G Jul 25 '17 at 07:28
  • This answer is some kind of mess, the static helper which is posted here would not work!. The is no class ViewWebPage, but WebViewPage. Also what is ViewData? The ViewData is not refering and it is not global class in MVC. No way this code would work. – Tomas Nov 16 '18 at 13:00
  • @Tomas a simple *I think you misspelled WebViewPage as ViewWebPage* would suffice. [System.Web.Mvc.WebViewPage | Properties | ViewData](https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.webviewpage.viewdata?view=aspnet-mvc-5.2#System_Web_Mvc_WebViewPage_ViewData). With 61 up-votes (so far) others have figured it out, it's really not to hard. – Erik Philips Nov 16 '18 at 16:53
  • @Erik, that I want to say that not I but you misspelled ViewWebPage class name and after you have corrected the class name your extension method still wouldn't work. I didn't try to run it but ViewData would be not found in that extension method scope. You didn't tested your code either :) – Tomas Nov 17 '18 at 11:54
  • really good and clear way to set properties to the html controls – AlejandroDG Mar 28 '19 at 15:02
21

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

[Required]
public string ShortName {get; set;}
Floremin
  • 3,969
  • 15
  • 20
13

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.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
bvpb
  • 1,416
  • 22
  • 31
  • 1
    Your entire method body could simply be replaced with `return validatorMetadata.Any(vm => vm is RequiredAttribute)` – Erik Philips Sep 07 '17 at 13:44
  • @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 – bvpb Sep 08 '17 at 01:49
  • 2
    Nice. I feel like they should build this in as part of ASP.NET Core. – Seafish Oct 08 '17 at 05:50
3

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

<%: Html.TextBoxFor(model => model.Name, new { @required = true })%>
hestellezg
  • 3,309
  • 3
  • 33
  • 37
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.

Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265
  • 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 http://www.asp.net/web-pages/overview/getting-started/introducing-razor-syntax-c – Stephan Luis Jan 29 '16 at 15:04
  • should be @Html.TextBoxFor(m => m.ShortName, new { data_val_required = "You need me" }) without the semicolon. – Stephan Luis Jan 29 '16 at 21:41
  • This doesn't answer the question. – Erik Philips Feb 10 '17 at 08:13