Mister Epic
Mister Epic

Reputation: 16743

Optional attributes in tag helpers

I have a tag helper along the lines of the following:

[HtmlTargetElement("foo", Attributes = "bar")]
public class FooTagHelper : TagHelper

[HtmlAttributeName("bar")]
public bool Bar { get; set; }

When I add the following to a view, the tag helper processes the target as expected:

<foo bar="true"></foo>

However, what I would like to do is make bar optional e.g. <foo></foo> If it has been left off, I would like it to default to false

Is this possible? This source code comment for the HtmlTargetElementAttribute.Attributes property seems to indicate not:

// Summary:
A comma-separated System.String of attribute names the HTML element must contain
for the Microsoft.AspNet.Razor.TagHelpers.ITagHelper to run. * at the end of an attribute name acts as a prefix match.

Upvotes: 4

Views: 4574

Answers (3)

chandler
chandler

Reputation: 1150

The only way I was able to get attributes to be optional is if I did not include them in the Attributes section of HtmlTargetElement.

so this [HtmlTargetElement("foo", Attributes = "bar")] changes to [HtmlTargetElement("foo")]

then also remove the [HtmlAttributeName("bar")] here:

[HtmlAttributeName("bar")]
public bool Bar { get; set; }

so completed changes look like:

[HtmlTargetElement("foo")]
public class FooTagHelper : TagHelper
{
   public bool Bar { get; set; }
   public string FooBar { get; set; }
}

also make sure any properties you reference in your tag are kebab-case, example:

<foo bar="true" foo-bar="make sure to use kebab-case!"></foo>

Upvotes: 0

Erik Stroeken
Erik Stroeken

Reputation: 559

If you wan't to check if the optional attribute is explicitly specified in the Html, you can check context.AllAttributes, you won't find it in output.Attributes as specified in the previous post.

I noticed that my TagHelper wasn't rendered if I left away the (optional) attribute OnlyUrlOfMenuItem in the Html. I just had to remove the attribute OnlyUrlOfMenuItem from the list of required attributes HtmlTargetElement() as stated by Mat Hellums above. Since I don't want this attribute to appear in the final output, I didn't need to add the attribute with output.Attributes.Add() as stated in the previous post.

Here is my code with the optional attribute OnlyUrlOfMenuItem that has a default value of false:

[HtmlTargetElement("a", Attributes = "MenuItem, LangCode")]
public class ATagHelper : TagHelper
{
    readonly IFhpMenuProvider _fhpMenuProvider;

    public ATagHelper(IFhpMenuProvider fhpMenuProvider)
    {
        _fhpMenuProvider = fhpMenuProvider;
        OnlyUrlOfMenuItem = false;
    }

    [HtmlAttributeName("LangCode")]
    public string LangCode { get; set; }

    [HtmlAttributeName("MenuItem")]
    public string MenuItemKey { get; set; }

    [HtmlAttributeName("OnlyUrlOfMenuItem")]
    public bool OnlyUrlOfMenuItem { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        MenuItem menuItem = _fhpMenuProvider.GetMenuItem(MenuItemKey, LangCode);
        if (menuItem != null)
        {
            ...
            if (string.IsNullOrEmpty(menuItem.Tooltip) == false && OnlyUrlOfMenuItem == false)
            {
                output.Attributes.SetAttribute("title", menuItem.Tooltip);
            }
            if (string.IsNullOrEmpty(menuItem.Caption) == false && OnlyUrlOfMenuItem == false)
            {
                output.Content.SetContent(menuItem.Caption);
            }
        }
        base.Process(context, output);
    }

Upvotes: 1

Mat Hellums
Mat Hellums

Reputation: 382

You could remove "bar" from being a required attribute.

You can do that by overriding the Process method and checking whether the attribute exists. If it does not, add the Bar attribute using its name and value. You could explicitly set the value to false but the property Bar is false by default anyway.

[HtmlTargetElement("foo")]
public class FooTagHelper : TagHelper
{
    [HtmlAttributeName("bar")]
    public bool Bar { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (!output.Attributes.ContainsName(nameof(Bar)))
        {
            output.Attributes.Add(nameof(Bar), Bar);
        }
    }
}

Cheers!

If you have not yet done so, I would suggest taking a look at the documentation available here https://docs.asp.net/projects/mvc/en/latest/views/tag-helpers/index.html.

Upvotes: 7

Related Questions