In a previous blog post we talked about how to create a simple tag helper in MVC 6. In today's post we take this one step further and create a more complex tag helper that is made up of multiple parts.
A Tag Helper for Bootstrap Modal Dialogs
Creating a modal dialog in bootstrap requires some verbose html.
Using a tag helper here would help simplify the markup but this is a little more complicated than the Progress Bag example. In this case, we have HTML content that we want to add in 2 different places: the
<div class="modal-body"></div> element and the
<div class="modal-footer"></div> element.
The solution here wasn't immediately obvious. I had a chance to talk to Taylor Mullen at the MVP Summit ASP.NET Hackathon in November and he pointed me in the right direction. The solution is to use 3 different tag helpers that can communicate with each other through the
Ultimately, we want our tag helper markup to look like this:
This solution uses 3 tag helpers:
modal-footer. The contents of the
modal-body tag will be placed inside the
<div class="modal-body"></div> while the contents of the
<modal-footer> tag will be placed inside the
<div class="modal-footer"></div> element. The
modal tag helper is the one that will coordinate all this.
Restricting Parents and Children
First things first, we want to make sure that
<modal-footer> can only be placed inside the
<modal> tag and that the
<modal> tag can only contain those 2 tags. To do this, we set the
RestrictChildren attribute on the modal tag helper and the
ParentTag property of the
HtmlTargetElement attribute on the modal body and modal footer tag helpers:
Now if we try to put any other tag in the
<modal> tag, Razor will give me a helpful error message.
Getting contents from the children
The next step is to create a context class that will be used to keep track of the contents of the 2 child tag helpers.
At the beginning of the ProcessAsync method of the Modal tag helper, create a new instance of
ModalContext and add it to the current
Now, in the modal body and modal footer tag helpers we will get the instance of that
ModalContext via the
TagHelperContext. Instead of rendering the output, these child tag helpers will set the the
Footer properties of the
Back in the modal tag helper, we call
output.GetChildContentAsync() which will cause the child tag helpers to execute and set the properties on the
ModalContext. After that, we just set the output as we normally would in a tag helper, placing the
Footer in the appropriate elements.
Composing complex tag helpers with parent / child relationships is fairly straight forward. In my opinion, the approach here is much easier to understand than the "multiple transclusion" approach used to solve the same problem in Angular 1. It would be easy to unit test and as always, Visual Studio provides error messages directly in the HTML editor to guide anyone who is using your tag helper.
You can check out the full source code on the Tag Helper Samples repo.