Reputation: 2551
I need to automatically display an asterisk for required fields, so I've managed to find some code online that does this. I've added a CSS Class named "required-label" to also turn it red. However, it only applies the CSS class to the asterisk and not the label too. Any ideas how to apply the CSS class to both? Here's the full snippet as requested.
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Threading.Tasks;
namespace App.TagHelpers
{
[HtmlTargetElement("label", Attributes = ForAttributeName)]
public class LabelRequiredTagHelper : LabelTagHelper
{
private const string ForAttributeName = "asp-for";
public LabelRequiredTagHelper(IHtmlGenerator generator) : base(generator)
{
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
await base.ProcessAsync(context, output);
if (For.Metadata.IsRequired)
{
var sup = new TagBuilder("sup");
sup.InnerHtml.Append("*");
sup.AddCssClass("required-label");
output.Content.AppendHtml(sup);
}
}
}
}
Credit to Manoj Kulkarni for the code example.
Upvotes: 3
Views: 3724
Reputation: 21476
The tag helper in the OP works, but instead of appending a sup element to contain the asterisk, I think all you need to do is to add a css class to the label element itself and use CSS to style the label accordingly.
tag-helper
[HtmlTargetElement("label", Attributes = ForAttributeName)]
public class LabelRequiredTagHelper : LabelTagHelper
{
private const string ForAttributeName = "asp-for";
private const string RequiredCssClass = "required";
public LabelRequiredTagHelper(IHtmlGenerator generator) : base(generator)
{
}
public override async Task ProcessAsync(TagHelperContext context,
TagHelperOutput output)
{
await base.ProcessAsync(context, output);
if (For.Metadata.IsRequired)
{
output.Attributes.AddCssClass(RequiredCssClass);
}
}
}
AddCssClass
extensionpublic static class TagHelperAttributeListExtensions
{
public static void AddCssClass(this TagHelperAttributeList attributeList,
string cssClass)
{
var existingCssClassValue = attributeList
.FirstOrDefault(x => x.Name == "class")?.Value.ToString();
// If the class attribute doesn't exist, or the class attribute
// value is empty, just add the CSS class
if (String.IsNullOrEmpty(existingCssClassValue))
{
attributeList.SetAttribute("class", cssClass);
}
// Here I use Regular Expression to check if the existing css class
// value has the css class already. If yes, you don't need to add
// that css class again. Otherwise you just add the css class along
// with the existing value.
// \b indicates a word boundary, as you only want to check if
// the css class exists as a whole word.
else if (!Regex.IsMatch(existingCssClassValue, $@"\b{ cssClass }\b",
RegexOptions.IgnoreCase))
{
attributeList.SetAttribute("class", $"{ cssClass } { existingCssClassValue }");
}
}
}
A sample view model that contains required properties, annotated with [Required]
. Also a boolean is required by default.
public class LoginViewModel
{
[Required]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember my login?")]
public bool RememberMe { get; set; }
public string ReturnUrl { get; set; }
}
For example, I have a login page that takes LoginViewModel
.
@model LoginViewModel
@{
ViewData["Title"] = "Login";
}
<form asp-area="" asp-controller="account" asp-action="login">
<input type="hidden" asp-for="ReturnUrl" />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Email"></label>
<input type="email" class="form-control" asp-for="Email" />
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input type="password" class="form-control" asp-for="Password" />
</div>
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" asp-for="RememberMe" />
<label asp-for="RememberMe" class="custom-control-label"></label>
</div>
</div>
<button type="submit" class="btn btn-primary btn-block">Login</button>
</form>
Worth knowing that the label for checkbox RememberMe
. On the view I have added additional css class custom-control-label
, and the tag helper still manages to add the required css class required
along with it.
You can tell I am using Bootstrap css framework and there are already styles for checkbox labels so I want to exclude those (denoted by custom-control-label
css class).
label.required:not(.custom-control-label)::after {
content: "*";
padding-left: .3rem;
color: theme-color('danger'); /* color: #dc3545; */
}
If you want the required label to be red too, you can style it this way:
label.required:not(.custom-control-label) {
color: theme-color('danger'); /* color: #dc3545; */
&::after {
content: "*";
padding-left: .3rem;
}
}
Upvotes: 5