Trigger TagHelper from another TagHelper
Asked Answered
L

1

6

I would like to trigger the stock ScriptTagHelper (view source on GitHub) so that it would emulate the asp-append-version="true" attribute.

I know that the proper way to use this is to just change from this:

<script src="somefile.js"></script>

to this:

<script src="somefile.js" asp-append-version="true"></script>

This process is very similar for versioning CSS includes and images (LinkTagHelper and ImageTagHelper).

Since I have a lot of included scripts, stylesheets, and images, I would like to automate things a bit. So instead of adding asp-append-version="true" on each and every HTML element, I would rather create a custom TagHelper that does this for me.

Herein lies the problem - it does not work.

Currently, my TagHelper covers only script tags and looks like this:

  [HtmlTargetElement("script", Attributes = "src")]      
  public class TestTagHelper : TagHelper
  {
    public override int Order => int.MinValue;
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
      if(!context.AllAttributes.ContainsName("asp-append-version"))
      {
        output.Attributes.SetAttribute("asp-append-version", "true");
      }
    }
  }

But instead of triggering the default ScriptTagHelper, it literally outputs the asp-append-version="true" to the output HTML. I have also set the Order property to INT_MIN, so that it fires before any other Tag Helpers, but it still doesn't work.

Is there a way to make this work?

Ludmilla answered 14/6, 2018 at 12:7 Comment(3)
ASP.NET Core does not apply multiple tag helpers. Once one matches, that is the one that renders the output and that's it. If you want to do something like this, I would suggest inheriting from ScriptTagHelper and simply modifying it to apply the append version by default. It would probably be as simple as setting the backing property to be true by default instead of false, but I haven't looked at the code.Shipway
I have tried with sub-classing and setting the property to true, but It also didn't work properly. I didn't known that only one tag helper is applied, I find this is really weird, since Tag Helper chaining would be very useful.Ludmilla
If tag helpers could be chained then you could not ever use a tag helper with the same name as an HTML element. Things like the ScriptTagHelper work, because it makes a single pass over the script tags and then assumes rendered HTML. If it continued to look for tag helpers, then it would run the ScriptTagHelper again... and then again.. ad infinitum.Shipway
R
6

As @ChrisPratt mentioned, chaining TagHelpers is not possible. There is a little, dirty trick which might help you out. You could new up an instance of ScriptTagHelper manually in your own tag helper and invoke the Process method manually:

[HtmlTargetElement("script", Attributes = "src")]
public class TestTagHelper : TagHelper
{
    public override int Order => int.MinValue;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (!context.AllAttributes.ContainsName("asp-append-version"))
        {
            var scriptTagHelper = new ScriptTagHelper(...) // Inject the required dependencies here
            {
                AppendVersion = true, // Explicitly set to true
                // Map all other properties
            };
            scriptTagHelper.Process(context, output);
        }
    }
}
Reactor answered 14/6, 2018 at 18:20 Comment(1)
If the script does not contain any asp-* attributes, then this not work, because of the AttributeMatcher.TryDetermineMode problem. See #50959031 for an approach to overcoming that.Entourage

© 2022 - 2024 — McMap. All rights reserved.