TagHelpers add custom class for LabelTagHelper based on validation attribute [Required]
Asked Answered
B

3

5

In Core MVC there is anew concept as Tag helpers.

We could previously create custom html helpers to attach some classes based on the validation data annotations such as [Required].

As TagHelpers arq quite new area I cannot find anough resources to achieve the following:

here is the view model:

    [Required]
    public Gender Gender { get; set; }

view:

<label class="control-label col-md-3 required" asp-for="Gender"></label>

css:

.required:after {
content: "*";
font-weight: bold;
color: red;
}

output: enter image description here

But I don't want to manully add the required css class in the label. Somehow I shoudl be able to extend the LabelTagHelper to read model data annotations and if it has the [Required] then add required class in the label element.

Thanks,

Bruis answered 10/12, 2016 at 3:6 Comment(0)
F
7

Yup, you can extend this pretty easily by inheriting from the LabelTagHelper class and adding in your own class to the attribute list first.

[HtmlTargetElement("label", Attributes = "asp-for")]
public class RequiredLabelTagHelper : LabelTagHelper
{
    public RequiredLabelTagHelper(IHtmlGenerator generator) : base(generator)
    {
    }

    public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        if (For.Metadata.IsRequired)
        {
            CreateOrMergeAttribute("class", "required", output);
        }

        return base.ProcessAsync(context, output);
    }

    private void CreateOrMergeAttribute(string name, object content, TagHelperOutput output)
    {
        var currentAttribute = output.Attributes.FirstOrDefault(attribute => attribute.Name == name);
        if (currentAttribute == null)
        {
            var attribute = new TagHelperAttribute(name, content);
            output.Attributes.Add(attribute);
        }
        else
        {
            var newAttribute = new TagHelperAttribute(
                name,
                $"{currentAttribute.Value.ToString()} {content.ToString()}",
                currentAttribute.ValueStyle);
            output.Attributes.Remove(currentAttribute);
            output.Attributes.Add(newAttribute);
        }
    }
}
Fort answered 13/12, 2016 at 4:6 Comment(3)
I will try soon and accept the answer. It looks like it will work. ThanksBruis
Yeap this works perfect. it is worth mentioning that once the custom tag helper is created it must be referenced in _ViewImports.cshtml file to work. something like: @addTagHelper "*, WebApplicaiton.Web"Bruis
I realize this is a bit old however you might want to change var attribute = new TagHelperAttribute("class", content); to var attribute = new TagHelperAttribute(name, content); as this is susposed to be attribute name agnostic the coded class name seems incorrect to me.Otherwise +1 for me.Indoeuropean
C
2

For answer by Will Ray, I'd like to make a change to the override ProcessAsync as:

public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)

{     

     var isRequired = For.Metadata.ValidatorMetadata.Any(x => 
                         x.GetType().Name.Equals("RequiredAttribute"));
     if (isRequired)
     {
          CreateOrMergeAttribute("class", "required", output);
     }

     return base.ProcessAsync(context, output);
}

Since For.Metadata.IsRequired is always true for boolean properties.

Cupreous answered 12/3, 2019 at 17:30 Comment(1)
not only boolean properties, but all value type propertiesThromboplastin
T
0

As the treatment for Value and Reference types is different, the following code could help:

public override async Task ProcessAsync(TagHelperContext context,TagHelperOutput output)
{
    await base.ProcessAsync(context, output);

    if (RequiredAttributeExists(For.Metadata))
    {
        output.AddClass("required", HtmlEncoder.Default);
    }
}

private static bool RequiredAttributeExists(ModelMetadata metaData)
{
    if (metaData.ModelType.IsValueType)
    {
        return metaData.ValidatorMetadata.Any(x => x is RequiredAttribute);
    }
    else // not value type
    {
        return metaData.IsRequired;
    }
}
Thromboplastin answered 1/6, 2021 at 8:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.