Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tag helper `Attributes` alias

I couldn't find any way to give multiple names to a single tag helper (alias) in netcore20 to the following tag helper class definition

[HtmlTargetElement(Attributes = AttributeName)]
public class InDomIfTagHelper : TagHelper
{
    private const string AttributeName = "idi,in-dom-if";

    [HtmlAttributeName(AttributeName)]
    public bool InDomIf { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        base.Process(context, output);
        if (!InDomIf)
        {
            output.SuppressOutput();
        }
    }
}

I would like to be able to refer to my tag helper using both of the following syntaxes

<li idi='false'>content</li>
<li in-dom-if="true">content2</li>

I did some research and found posts such as this one on SO but makes both tag need (an AND clause, basically).

I still tried defining my Attributes property with "idi,in-dom-if" as well as "[idi],[in-dom-if]" the last one actually gave me an error : Invalid tag helper bound property

Admin.TagHelpers.InDomIfTagHelper.InDomIf'. Tag helpers cannot bind to HTML attributes with name '[idi],[in-dom-if]' because the name contains a ']' character.

I also tried this one "[name=idi],[name=in-dom-if]" and I added quotes around the tag names too ... none of this worked.

Since I can't seem to find much info about defining tag helper attributes names using an OR clause I wonder if it is even possible ...

I would like to avoid defining twice the same logic in two different classes just so they can have the same name.

Is this even possible ? If it is, how can I achieve this ?

like image 801
Mathieu VIALES Avatar asked Jan 30 '23 10:01

Mathieu VIALES


1 Answers

The HtmlTargetElement attribute specifies one set of selectors that are required to match in order to activate your tag helper. If you want to specify an alternate set of selectors, all you have to do is add another HtmlTargetElement attribute.

You can use the HtmlTargetElement as many times as you need to set up separate sets of selectors for your tag helper. The tag helper will activate when there is one HtmlTargetElement that has all its requirements matching.

This can get pretty extensive if you have a lot of alternative ways to activate your tag helper. For example, the built-in AnchorTagHelper looks like this:

[HtmlTargetElement("a", Attributes = ActionAttributeName)]
[HtmlTargetElement("a", Attributes = ControllerAttributeName)]
[HtmlTargetElement("a", Attributes = AreaAttributeName)]
[HtmlTargetElement("a", Attributes = PageAttributeName)]
[HtmlTargetElement("a", Attributes = PageHandlerAttributeName)]
[HtmlTargetElement("a", Attributes = FragmentAttributeName)]
[HtmlTargetElement("a", Attributes = HostAttributeName)]
[HtmlTargetElement("a", Attributes = ProtocolAttributeName)]
[HtmlTargetElement("a", Attributes = RouteAttributeName)]
[HtmlTargetElement("a", Attributes = RouteValuesDictionaryName)]
[HtmlTargetElement("a", Attributes = RouteValuesPrefix + "*")]
public class AnchorTagHelper : TagHelper
{ /* … */ }

As you can see, there is always the restriction on the a tag, and on one of the supported attributes. So in order to activate the tag helper, any of those attributes has to be used on an <a> element.


However, it is not possible to map two attributes to the same tag helper property. So even if you can specify two separate selectors to match either the in-dom-if or the idi attribute, it is not possible for one to be an exact alias of the other. You will have to map them individually. But you can have them share the same backing field, so you don’t need to handle both in the Process method:

[HtmlTargetElement(Attributes = AttributeName)]
[HtmlTargetElement(Attributes = ShortcutAttributeName)]
public class InDomIfTagHelper : TagHelper
{
    private const string AttributeName = "in-dom-if";
    private const string ShortcutAttributeName = "idi";

    [HtmlAttributeName(AttributeName)]
    public bool InDomIf { get; set; }

    [HtmlAttributeName(ShortcutAttributeName)]
    public bool InDomIfShortcut
    {
        get => InDomIf;
        set => InDomIf = value;
    }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        base.Process(context, output);
        if (!InDomIf)
        {
            output.SuppressOutput();
        }
    }
}

As for the idi,in-dom-if or [idi],[in-dom-if] syntax, this is only supported on the HtmlTargetElement attribute. It is used to set up multiple attribute selectors that all need to match in order for the HtmlTargetElement to match an element and activate the tag helper. So a [HtmlTargetElement(Attributes = "idi,in-dom-if")] will actually only activate the tag helper when there are both a idi and a in-dom-if attribute on the element (which is obviously not what you want here).

On the HtmlAttributeName attribute however, there only can be a single attribute name, since it has to be a clear 1-to-1 mapping. That is the thing that throws the error in your attempt. And that’s also why we have to use two properties above.

like image 84
poke Avatar answered Feb 02 '23 09:02

poke