Introduction To Tag Helpers

TAG Helpers

  • What are tag helpers? Advantages
  • Tag helper vs Html helper.
  • Why to use tag helpers?
  • Tag helper example
  • Tag helper steps
  • Tag helper class
  • Html tag helpers
  • Complex tag helper

What are Tag Helpers? Simple Example of Tag Helper, Advantages over HTML Helper

In our view we need some controls are html elements like form controls are heading element that help us to build View. Tag helpers help us to create that Html elements, we can extend existing html elements or we can have our own custom tags, Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.

Example of tag helper is,

Anchor tag : <a asp-action=”ActionName” asp-controller=”ControllerName” class=”customCssClass”>

tag

We already have some built in tag helpers which help us to have eat and clean Views. Like Label, Anchor, Form Controls like input type, select etc.

Advantages of using tag helper over HTML Helper is that it make things really neat like in above example we use simple html tag attribute class=”customCssClass” but in case of HtmlHelper we need to use special character like

new {@class="caption"}

Some advantages of using Tag Helpers

  • An HTML-friendly development experience
  • A rich IntelliSense environment for creating HTML and Razor markup
  • A way to make you more productive and able to produce more robust, reliable, and maintainable code using information only available on the server

Scope of Tag Helpers, How we can use them in our project?

You should have Microsoft.AspNetCore.Mvc.TagHelpers to use tag helpers in you project, whenever you create project from template Razor tools are installed so you don’t need to worry about it.
To use tag helpers in your view you need to have name space in your views, its good to import the name space in _ViewImports.cshtml file

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Now you have intellisence support of tag helper in your views.

If you have your custom tag defined in a folder “TagHelpers” in you project then you can import tag helpers folder like

@addTagHelper *, Tag_Helpers This “Tag_Helpers” is the main name space. Now it imports folders in views so you can declare your own custom tag helpers in view without worrying of including reference on each view.

@addTagHelper "*, projectname"

@removeTagHelper can also used to remove specific tag helpers of a namespace.

We can say that there different types of Tag Helper

  1. Tag helper that extend exsiting html tag
    We have already used anchor tag that takes asp-action and asp-controller as atribute and we render link according to provided attributes.

  2. Custom tag helper
    Later in this, we will define a custom tage helper that render a list of objects. We will use custom tag helper for that, which take list of string as parameter.

  3. Tag helper that helps to do some operations seemless and update some exsisting tags or their attributes.
    These tag helper are link environment , in the environment tag we can have group of files that need to be included on the base of environment like if environment is development get local javascript file but in case of production get files from CDN.

Custom Tag Helper

Custom tag helper can help you to have a tag helper that can perform some operations like in case if you want to have header tag just for example.

Step 1

Decide what Is your target tag and then create a class that should inherit from TagHelper. Please note that namming convention is important, if you have multiple words in name like mygrid then it can be used as my-grid in view (Kebab-Style). MyGridTagHelper class make the runtime to target the tag like my-grid.If you have simple class name like AlertTagHelper then you can simply use alert as tag name.

Step 2

Override the Process or ProcessAsync method that gives you output conetxt to perform operation,

  • TagHelperContext
    This parameter contains information about the tag addressed by the tag helper including all its attributes and children elements.

  • TagHelperOutput
    Used to generated the tag output.

Step 3

Use the tag in your view and pass the required attribute.

Custom tag helper example

  1. Target the div element which have a info-message attribute.
  2. Check the properties and render the boot starp info message.
    1. using Microsoft.AspNetCore.Razor.TagHelpers;  
    2. using System;  
    3. using System.Collections.Generic;  
    4. using System.Diagnostics;  
    5. using System.Linq;  
    6. using System.Threading.Tasks;  
    7. namespace Tag_Helpers.TagHelpers {  
    8.     [HtmlTargetElement("div", Attributes = InfoMessageAttributeName)]  
    9.     public class AlertMessageTagHelper: TagHelper {  
    10.         private  
    11.         const string InfoMessageAttributeName = "info-message";  
    12.         private  
    13.         const string MessageAttributeName = "message";  
    14.         private  
    15.         const string HideAttributeName = "visible";  
    16.         private  
    17.         const string AlertTypeAttributeName = "alert-type";  
    18.         [HtmlAttributeName(MessageAttributeName)]  
    19.         public string Message {  
    20.             get;  
    21.             set;  
    22.         }  
    23.         [HtmlAttributeName(HideAttributeName)]  
    24.         public bool Visible {  
    25.             get;  
    26.             set;  
    27.         }  
    28.         [HtmlAttributeName(AlertTypeAttributeName)]  
    29.         public string AlertType {  
    30.             get;  
    31.             set;  
    32.         }  
    33.         public override void Process(TagHelperContext context, TagHelperOutput output) {  
    34.             string className = string.Empty;  
    35.             if (Visible) {  
    36.                 className = "show";  
    37.             } else {  
    38.                 className = "hidden";  
    39.             }  
    40.             Debug.WriteLine("========================>" + context.UniqueId);  
    41.             string InfoMessageContent = $ @ "<div id='{context.UniqueId}' onclick='hideContent(this)' class='infoMessage alert alert-dismissable {AlertType} {className}'><a href ='#' class='close' data-dismiss='alert' aria-label='close'>×</a><strong>Information:</strong><span id='statusMessage' >{Message}</ span ></ div >";  
    42.             string js = "<script type='text/javascript'>function hideContent(e){ $(e).removeClass('show').addClass('hidden');} function showMessage(message){ var control= $('[info-message]'); $(control).find('span').text(message); }</script>";  
    43.             output.Content.AppendHtml(js + InfoMessageContent);  
    44.             base.Process(context, output);  
    45.         }  
    46.     }  
    47. }  

Let me share how it can use in View,

  1. @using Tag_Helpers.Controllers;  
  2. @model IEnumerable < Tag_Helpers.Controllers.Data > @  
  3.   {  
  4.     ViewData["Title"] = "Home Page";  
  5. } < script type = "text/javascript" > function UpdateMessageContent()  
  6. {  
  7.     var message = $("#txt1").val();  
  8.     showMessage(message);  
  9. } < /script> < div info - message message = "A simple message"  
  10. visible = "true"  
  11. alert - type = "alert-info" > < /div> < input type = "text"  
  12. id = "txt1" / > < input type = "button"  
  13. onclick = "UpdateMessageContent()"  
  14. value = "Update Message Content" / >   

Output

tag
When I add some text in textbox and click on Update Message Button then it updates the message content

tag

Explanation

We declared a class AlertMessageTagHelper, this class target HtmlElement div so we have declared attribute of class like, 

  1. [HtmlTargetElement("div", Attributes = InfoMessageAttributeName)]  
  2.   
  3. //And  
  4.   
  5. private const string InfoMessageAttributeName = "info-message";   

We have defined class property along with HtmlAttribute that is required to target, 

  1. private  
  2. const string MessageAttributeName = "message";  
  3. [HtmlAttributeName(MessageAttributeName)]  
  4. public string Message  
  5. {  
  6.     get;  
  7.     set;  
  8. }   

So we have other properties like that and we follow same procedure.

When we have any div html element with the info-message attribute then it target this tag helper.

We pass the message,visible and alert type attribute , alert type attribute can be alert-danger, alert-info etc.

  1. <div info-message message="A simple message" visible="true" alert-type="alert-info"></div>  

 

Example of custom Tag Helper

Objective of this tag to render html table which is passed from view by using grid tag helper.

This is custom tag helper example. 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;  
  6. using Microsoft.AspNetCore.Razor.TagHelpers;  
  7. using Microsoft.AspNetCore.Mvc.Rendering;  
  8. using System.Reflection;  
  9. namespace Tag_Helpers.TagHelpers {  
  10.     [HtmlTargetElement("grid")]  
  11.     public class GridTagHelper: TagHelper {  
  12.         private  
  13.         const string ItemsAttributeName = "items";  
  14.         [HtmlAttributeName(ItemsAttributeName)]  
  15.         public IEnumerable < object > Items {  
  16.             get;  
  17.             set;  
  18.         }  
  19.         public override void Process(TagHelperContext context, TagHelperOutput output) {  
  20.             TagBuilder table = new TagBuilder("table");  
  21.             table.GenerateId("id", context.UniqueId);  
  22.             var attributes = context.AllAttributes.Where(atr => atr.Name != ItemsAttributeName).ToDictionary(atr => atr.Name, atr => atr.Value);  
  23.             table.MergeAttributes < string, object > (attributes);  
  24.             var tr = new TagBuilder("tr");  
  25.             var heading = Items.First();  
  26.             PropertyInfo[] properties = heading.GetType().GetProperties();  
  27.             foreach(var prop in properties) {  
  28.                 TagBuilder headerCol = new TagBuilder("th");  
  29.                 headerCol.InnerHtml.Append(prop.Name.ToString());  
  30.                 tr.InnerHtml.AppendHtml(headerCol);  
  31.             }  
  32.             table.InnerHtml.AppendHtml(tr);  
  33.             foreach(var item in Items) {  
  34.                 tr = new TagBuilder("tr");  
  35.                 foreach(var prop in properties) {  
  36.                     TagBuilder col = new TagBuilder("td");  
  37.                     col.InnerHtml.Append(prop.GetValue(item).ToString());  
  38.                     tr.InnerHtml.AppendHtml(col);  
  39.                 }  
  40.                 table.InnerHtml.AppendHtml(tr);  
  41.             }  
  42.             output.Content.SetHtmlContent(table);  
  43.         }  
  44.     }  
  45. }   

We can define a class in project like. 

  1. public class Test  
  2. {  
  3.     public string Name {  
  4.         get;  
  5.         set;  
  6.     }  
  7.     public string Email {  
  8.         get;  
  9.         set;  
  10.     }  
  11. }   

We can use that class in View like, don’t forget to import class namespace in view if it is not accessible in view. 

  1. @ {  
  2.     List < Test > tests = new List < Test > ();  
  3.     Test t1 = new Test();  
  4.     t1.Name = "Khuram";  
  5.     t1.Email = "khuram.mails@gmail.com";  
  6.     Test t2 = new Test();  
  7.     t2.Name = "Khuram";  
  8.     t2.Email = "khuram.mails@gmail.com";  
  9.     tests.Add(t1);  
  10.     tests.Add(t2);  
  11. } < grid items = "@tests"  
  12. border = "1" > < /grid>   

Output in the view is like this

tag
Explanation

We have declared a class and use 

  1. [HtmlTargetElement("grid")]  
  2. public class GridTagHelper : TagHelper   

Now this class target a custom tag ehich is <grid> this grid tag expect some attributes 

  1. private  
  2. const string ItemsAttributeName = "items";  
  3. [HtmlAttributeName(ItemsAttributeName)]  
  4. public IEnumerable < object > Items  
  5. {  
  6.     get;  
  7.     set; 
  8. }   

items is the attribute name which should be passed from view , it is collection of object and that object can be a class like we pass object collection of class Test. 

  1. TagBuilder table = new TagBuilder("table");  
  2. table.GenerateId("id", context.UniqueId);   

We build a tag using TagBuilder class and assign the unique id to table. 

  1. var attributes = context.AllAttributes.Where(atr => atr.Name != ItemsAttributeName).ToDictionary(atr => atr.Name, atr => atr.Value);  
  2. table.MergeAttributes<string, object>(attributes);   

If there is any attribute defined on grid tag then merge it. 

  1. var tr = new TagBuilder("tr");  
  2. var heading = Items.First();  
  3. PropertyInfo[] properties = heading.GetType().GetProperties();  
  4. foreach(var prop in properties) {  
  5.     TagBuilder headerCol = new TagBuilder("th");  
  6.     headerCol.InnerHtml.Append(prop.Name.ToString());  
  7.     tr.InnerHtml.AppendHtml(headerCol);  
  8. }  
  9. table.InnerHtml.AppendHtml(tr);   

Create row and for each property of class , create header cell of table. 

  1. foreach(var item in Items)   
  2. {  
  3.     tr = new TagBuilder("tr");  
  4.     foreach(var prop in properties) {  
  5.         TagBuilder col = new TagBuilder("td");  
  6.         col.InnerHtml.Append(prop.GetValue(item).ToString());  
  7.         tr.InnerHtml.AppendHtml(col);  
  8.     }  
  9.     table.InnerHtml.AppendHtml(tr);  
  10. }   

Create row for an object and populate data.

  1. output.Content.SetHtmlContent(table);  

 

Render the table.

Complex Tag Helper

Sometime things are not simple so we need to have complex tag helper, where we can have tag inside tag or a parent tag can have child tags.

Example 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;  
  6. using Microsoft.AspNetCore.Razor.TagHelpers;  
  7. namespace Tag_Helpers.TagHelpers {  
  8.     [HtmlTargetElement("combo")]  
  9.     public class ComboTagHelper: TagHelper {  
  10.         [HtmlAttributeName("key")]  
  11.         public string Key {  
  12.             get;  
  13.             set;  
  14.         }  
  15.         [HtmlAttributeName("value")]  
  16.         public string Value {  
  17.             get;  
  18.             set;  
  19.         }  
  20.         [HtmlAttributeName("dsource")]  
  21.         public object DataSource {  
  22.             get;  
  23.             set;  
  24.         }  
  25.         [HtmlAttributeName("dclass")]  
  26.         public string DataClass {  
  27.             get;  
  28.             set;  
  29.         }  
  30.         public MultiSelectionTagHelper MultiSelection {  
  31.             get;  
  32.             set;  
  33.         }  
  34.         public override async void Process(TagHelperContext context, TagHelperOutput output) {  
  35.             context.Items.Add(typeof(ComboTagHelper), this);  
  36.             var childContent = await output.GetChildContentAsync();  
  37.             //Render items here  
  38.         }  
  39.     }  
  40. }  
  41. using System;  
  42. using System.Collections.Generic;  
  43. using System.Linq;  
  44. using System.Threading.Tasks;  
  45. using Microsoft.AspNetCore.Razor.Runtime.TagHelpers;  
  46. using Microsoft.AspNetCore.Razor.TagHelpers;  
  47. namespace Tag_Helpers.TagHelpers {  
  48.     [HtmlTargetElement("combo-multi-selection")]  
  49.     public class MultiSelectionTagHelper: TagHelper {  
  50.         [HtmlAttributeName("enable-checkboxes")]  
  51.         public bool EnableCheckBoxes {  
  52.             get;  
  53.             set;  
  54.         }  
  55.         [HtmlAttributeName("is-enabled")]  
  56.         public bool Enabled {  
  57.             get;  
  58.             set;  
  59.         }  
  60.         public override void Process(TagHelperContext context, TagHelperOutput output) {  
  61.             ((ComboTagHelper) context.Items[typeof(ComboTagHelper)]).MultiSelection = this;  
  62.             output.SuppressOutput();  
  63.         }  
  64.     }  
  65. }   

In the view we have, 

  1. <combo dsource="@Model" key="Id" value="Name">  
  2.     <combo-multi-selection is-enabled="true" enable-checkboxes="true" dclass="Data" />   
  3.  </combo>   

In the parent <combo> tag we have another tag which specify the multi selection and data class by dclass attribute.

We can get the child tag properties by

Defining child tag helper class object in parent class.

Add the parent class in the current context.

Get the class object from context in child tag helper class.

Now you can assigned the child tag helper object to parent.

Reference

http://Asp.Net