An easy Taghelper to make an element ‘active’ when clicked using Razor.0 Reacties

Still using backend HTML logic.

ASP.NET Core makes things a lot more easier for us, backend developers. Though, accent today, is more on frontend development, still, for reasons of security for instance, backend state management is still used.

Now take a look at this tiny gem, a TagHelper.

A ‘which menu has been clicked-set-active-helper’

What it does, basically, is checking if a

  • element has an attribute activecheck. If so, it detects which ‘action-route’ was executed/is executing and if the name matches, it adds class=”active”. So the output will be  e.g.
  • active”>
  • e.g. in the Razor View I have:


                                           <li activecheck="true" data-menu="Index" >
                                                <a asp-controller="Home" asp-action="Index">Homea>
                                           

      I had to add a ‘data-menu’ attribute, because Taghelpers, can not, as far as I found, parse the raw Razor Markup, when using ‘GetChildContentAsync()’  for instance, it only gets the HTML output that’s already there, without Razor markup. So, I cannot parse the child anchor and retrieve asp-acction=”Index”.
      Therefore, I specify it again using data-menu=”Index”. Note, this is removed later by the taghelper.

      using Microsoft.AspNetCore.Html;
      using Microsoft.AspNetCore.Mvc.Controllers;
      using Microsoft.AspNetCore.Mvc.Infrastructure;
      using Microsoft.AspNetCore.Razor.TagHelpers;

      namespace ladidah.TagHelpers
      {
          [HtmlTargetElement("li", Attributes = "activecheck")]
          public class LiActiveHelper: TagHelper
          {
              public bool activecheck { get; set; }
              private readonly string menu;
              public LiActiveHelper(IActionContextAccessor httpContext)
              {
                  var currentRoute = (ControllerActionDescriptor)httpContext.ActionContext.ActionDescriptor;
                  menu = currentRoute.ActionName;
              }
              public override void Process(TagHelperContext context, TagHelperOutput output)
              {
                  if (activecheck)
                  {
                      var dataMenu = output.Attributes["data-menu"];
                   
                       if (dataMenu != null && dataMenu.Value is HtmlString str && str.Value == menu)
                      {
                          output.Attributes.RemoveAll("activecheck");
                          output.Attributes.RemoveAll("data-menu");
                          if (!output.Attributes.ContainsName("class"))
                          {
                              output.Attributes.SetAttribute("class", "active");
                          }
                      }               
                  }          
              }
          }
      }

      To activate this taghelper, I had to add the following line in my _ViewImports.cshtml file

      @addTagHelper ladidah.TagHelpers.LiActiveHelper, ladidah

      Benefit of IoC in ASP.NET Core.

      In my ConfigureServices method, in startup.cs I had to add the following line, in order to be able to get the action context of the current MVC Controller.

      public void ConfigureServices(IServiceCollection services)
             {

      // code removed for readability

        services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

      }

      I hope you find this snippet useful.

    Give your C# class Initializer support0 Reacties

    Would you like a to boost your class which hosts a collection, and utilize a cool C# language feature, which is collection initializer support?

    For instance var myList = new List() {1,3,4} where {1,3,4} is the initializer.

    The basic idea is to implement IEnumerable, and IEnumerator and the class must have an ‘Add’ method with the correct signature.

    I made the class generic so you can initialize any array (ok, not for structs and simple types, but you modify a few things and that works too)

    // our sample class for iteration feeding

    public class Address
       {
           public string Street { get; set; }
           public string StreetNumber { get; set; }
           public string ZipCode { get; set; }
           public string City { get; set; }
       }
       public static class Program
       {
           static void Main()
           {
               var t = new ClassWithInitializerSupport

    {
                   new Address()
                   {
                       Street = "Mainstr.",
                       StreetNumber = "1",
                       City ="London"
                   },
                  new Address()
                   {
                       Street = "De Dam",
                       StreetNumber = "1",
                       City ="Amsterdam"
                   },
                   new Address()
                   {
                       Street = "Mangostreet",
                       StreetNumber = "123",
                       City ="New York"
                   }
               };
               foreach(var a in t)
               {
                   Console.WriteLine("Street {0}, City {1}", a.Street, a.City);
               }

    }

    public class ClassWithInitializerSupport : IEnumerable, IEnumerator where T : class
       {
           public ClassWithInitializerSupport()
           {
               arr = (T[])Array.CreateInstance(typeof(T), 0);
               pos = -1;
           }
           private T[] arr;
           private int pos;
           public T Current => arr[pos];

           object IEnumerator.Current => arr[pos];

           public void Dispose()
           {

           }

           public IEnumerator GetEnumerator()
           {
               return this;
           }
           public void Add(T v)
           {
               var p = arr.Length;
               Array.Resize(ref arr, p + 1);
               arr[p] = v;
           }
           public bool MoveNext()
           {
               if (pos + 1 < arr.Length)
               {
                   pos++;
                   return true;
               }
               return false;
           }

           public void Reset()
           {
               pos = -1;
           }

           IEnumerator IEnumerable.GetEnumerator()
           {
               return this;
           }
       }

    Fill a dropdownlist using the current UICulture in (ASP.NET)0 Reacties

    Just for educational purpose (as for myself as well :) ) I post this code.

    Using this, a programmer can use a good practise, that is to use the culture information which is built in, into .NET instead of making that data him/herself.

    based upon the following element in web.Config, the list will fill using the correct number of monthnames. It also keeps track of calendars, that have 13 months in some cultures.

    <globalization uiCulture="nl-nl"/>

    using System;

    using System.Collections.Generic;

    using System.Web;

    using System.Linq;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Threading;

    using System.Globalization;

    public partial class _Default : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            int monthNumber = 0;

            CultureInfo ci = Thread.CurrentThread.CurrentUICulture;

            var myMonthnames = ci.DateTimeFormat.MonthNames

                .Take(ci.Calendar.GetMonthsInYear(DateTime.Today.Year)).Select(p => new { monthNo = ++monthNumber, monthName = p });

            ddlMonthnames.DataTextField = "monthName";

            ddlMonthnames.DataValueField = "monthNo";

            ddlMonthnames.DataSource = myMonthnames;

            ddlMonthnames.DataBind();

        }

    }

    <select name="ddlMonthnames" id="ddlMonthnames">

    <option value="1">januarioption>

    <option value="2">februarioption>

    <option value="3">maartoption>

    <option value="4">apriloption>

    <option value="5">meioption>

    <option value="6">junioption>

    <option value="7">julioption>

    <option value="8">augustusoption>

    <option value="9">septemberoption>

    <option value="10">oktoberoption>

    <option value="11">novemberoption>

    <option value="12">decemberoption>

    select>