View Component or Tag Helper?
View components and tag helpers are nice features of ASP.NET Core that allow us to encapsulate some UI logic and avoid repeating the same code in different views.
Join the DZone community and get the full member experience.
Join For FreeSuppose you are working on an ASP.NET Core web application. To avoid havingn the views and layouts grow massively, you plan to separate some parts of these to independent components. This way you don't repeat code you wrote once. You find view components and tag helpers, but which one should you use?
The Difference Between View Components and Tag Helpers
It's important to understand what is what before doing any work.
- View components are like partial views with no model binding. View components have a backing component class with the
InvokeAsync()
method. They support dependency injection like controllers do. Similar to controllers, they support multiple views. - Tag helpers are classes that allow server-side code to participate in the rendering of HTML elements. The most famous tag helper is probablythe anchor tag helper that makes it possible to create MVC links using the <a> tag. Tag helpers support dependency injection but there's no support for external views. All markup is produced in tag helper code.
View component or tag helper? If it's something small, related to just few tags and no customizations are needed, then it's a tag helper; otherwise, it's view component.
Example: Assembly Version Tag Helper
I recently built a simple assembly version tag helper that I can use in projects where I have to display a web application version in thefooter of all pages. The implementation is simple — just write out the version and that's it.
[HtmlTargetElement("AssemblyVersion", TagStructure = TagStructure.NormalOrSelfClosing)]
public class AssemblyVersionTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "";
output.Content.Append(GetType().Assembly.GetName().Version.ToString());
}
}
There's no point in going with a view component here, as there's no need for views.
Example: Pager View Component
A pager view component is a different beast and it comes with the need for custom markup. A pager may come with default markup but in different projects we may have different markup for a pager.
A tag helper doesn't have support for multiple views and wrapping markup inside C# code would be crazy. Just take a look at the following fragment of a view component view and think if you want to implement it in pure C# code.
<ul class="pagination">
<li class="paginate_button page-item first" id="kt_table_1_first">
<a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + "1")">
<i class="la la-angle-double-left"></i>
</a>
</li>
<li class="paginate_button page-item previous" id="kt_table_1_previous">
<a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + (Model.CurrentPage-1))">
<i class="la la-angle-left"></i>
</a>
</li>
@for (var i = startIndex; i <= finishIndex; i++)
{
@if (i == Model.CurrentPage)
{
<li class="paginate_button page-item active">
<a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + i)">@i</a>
</li>
}
else
{
<li class="paginate_button page-item ">
<a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + i)">@i</a>
</li>
}
}
<li class="paginate_button page-item next" id="kt_table_1_next">
<a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + (Math.Min(Model.CurrentPage + 1, Model.PageCount)))">
<i class="la la-angle-right"></i>
</a>
</li>
<li class="paginate_button page-item last" id="kt_table_1_last">
<a tabindex="0" class="page-link" aria-controls="kt_table_1" href="@Html.Raw(urlTemplate + Model.PageCount)">
<i class="la la-angle-double-right"></i>
</a>
</li>
</ul>
Of course we can come out with a base tag helper for pager, define protected virtual method to output markup, and create custom implementations based on it, but it's against the idea of why a tag helper was invented. Let's say it's anti-pattern.
Here is an example of a pager view component that supports custom views.
public class PagerViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(PagedResultBase result, string viewName = "Default")
{
result.LinkTemplate = Url.Action(RouteData.Values["action"].ToString(), new { page = "{0}" });
return await Task.FromResult(View(viewName, result));
}
}
Compared to tag helpers, pager view components are easier to maintain as the view markup and view component code are separated.
Wrapping Up
View components and tag helpers are nice features of ASP.NET Core that allow us to encapsulate some UI logic and avoid repeating the same code in different views. We can use view components and tag helpers in shared projects and libraries. Tag helpers are for extending HTML elements with server-side logic. View components support custom views like controllers do and they are for cases when a component has more markup than just a few HTML tags.
Published at DZone with permission of Gunnar Peipman, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments