outline
Rendering a tag helper inside another tag helper
UPDATE: The content of the following post has been revisited with improvements in a more recent post check it out.
Lately, I was prototyping around the idea of creating asp.net core tag helper that will basically behave like the angular 2’s dynamic form. The idea is to have a tag helper that generates automatically a form from a C# model class in order to avoid coding the form cshtml by hand which can be sometimes tedious and repetitive.
During my fiddling I came across the need to render a tag helper inside the Process method of another tag helper.
In this post I wanted to share what I discovered so far, we are going to see a very striped down example of how to implement the aforementioned behavior. The full code for the example is available on Github.
The Example
In the previous screenshot the inner html p element having a red border is rendered from the InnerTagHelper, the outer html div having a black border is rendered from the WrapperTagHelper.
The WrapperTagHelper renders the InnerTagHelper programmatically inside its Process method. The following snippet shows how the WrapperTagHelper is used:
We can see here that we did not use the InnerTagHelper , yet it gets displayed.
InnerTagHelper
As we can see in the previous code the InnerTagHelper.Process method just sets the output html tag to be a p element, sets a class attribute for styling purposes and finally fills the content of the paragraph with the "This is from the inner tag helper" phrase.
Now let’s take a look at the WrapperTagHelper.
Rendering the InnerTagHelper
In order to render a TagHelper we need:
- an instance of the
TagHelperthat we wish to render - an instance of the
TagHelperContextclass - an instance of the
TagHelperOutputclass
The TagHelper.Process method is then called and the result can be accessed in the TagHelperOutput instance.
Consider the following snippet from the WrapperTagHelper’s code:
The WrapperTagHelper.Process method uses the private renderInnerTagHelper to get the content generated by the InnerTagHelper, let’s dissect this method.
First the InnerTagHelper class is instantiated, then in order to call the InnerTagHelper.Process we need to create a TagHelperOutput instance; this is done in the next statement.
The constructor for TagHelperOutput needs the following arguments:
tagNamewhich represents the output html tag name, in our case this is set insideInnerTagHelper.Processthat is why we just pass an empty string.attributesrepresents the list ofTagHelperAttributes, this list contains the html - attributes accessible fromoutput.Attributes, we just pass an empty list in our example since we don’t need to pass initial attributes toInnerTagHelpergetChildContentAsyncis a lambda expression that is supposed to asynchronously return the content of the renderedTagHelper, in our example we just pass a lambda expression that returns an emptyTagHelperContentobject sinceInnerTagHelperdoes not have child content.
Then we call the InnerTagHelper.Process method with the context and output argument. Note that in our example, we used the TagHelperContext passed to WrapperTagHelper.Process by the asp.net core machinery.
Finally, after calling Process output will be populated with the generated content. All we have to do now is to generate the actual Html tag before returning it.
Closing Thoughts
After a little a bit of experimentation, I still have some interrogations worth considering:
-
Is it OK to use the
contextinstance? Or should a new instance be created? perhaps a copy? -
How to create a
getChildContentAsynclambda in order to generate child content?
I will of course share the answers as soon as I get the interrogations figured out :-)