25

In an ASP.NET Core View I have the following:

<div class="message" message=""></div>

And I the a Tag Helper with the following TagHelper:

[HtmlTargetElement("div", Attributes = MessageName)]
public class MessageTagHelper : TagHelper {

  private const String MessageName = "message";

  [HtmlAttributeName(MessageName)]
  public String Message { get; set; }

  [HtmlAttributeNotBound, ViewContext]
  public ViewContext ViewContext { get; set; }


  public override void Process(TagHelperContext context, TagHelperOutput output) {

    String message;
    Boolean defined = ViewContext.HttpContext.Request.Cookies.TryGetValue("_message", out message);

    if (defined) {
      ViewContext.HttpContext.Response.Cookies.Delete("_message");
      output.Attributes.Add("class", "active");
      output.Content.Append(message);
    }
  }
}

On the following code line I need to add "active" as CSS Class.

output.Attributes.Add("class", "active");

However, this does nothing. Message remains only with class "message".

What am I missing?

0

4 Answers 4

48

As of ASP.NET Core 2.1 you can use the TagHelperOutputExtensions class provided by Microsoft to add your "active" CSS class in one line of code.

using Microsoft.AspNetCore.Mvc.TagHelpers;
using System.Text.Encodings.Web;
...
public override void Process(TagHelperContext context, TagHelperOutput output)
{
    ...
    output.AddClass("active", HtmlEncoder.Default);
    ...
}
Sign up to request clarification or add additional context in comments.

Comments

7

@Shyju's answer is mostly correct, but there's a lot of extraneous code that's unnecessary. The following is enough to handle it in ASP.NET Core 2.0:

var classes = output.Attributes.FirstOrDefault(a => a.Name == "class")?.Value;
output.Attributes.SetAttribute("class", $"active {classes}");

1 Comment

good! but this doesn't check for duplicate values if the class already contains new values to add. So, I post a more complete version here
2

I think you should remove the existing TagHelperAttribute for css class from the Attributes collection and add a new one which has all the classes (Existing and your new "active" class)

The below code should work.

var existingClass = output.Attributes.FirstOrDefault(f => f.Name == "class");
var cssClass = string.Empty;
if (existingClass != null)
{
    cssClass = existingClass.Value.ToString();       
}
cssClass = cssClass + " active";
var ta = new TagHelperAttribute("class", cssClass);
output.Attributes.Remove(existingClass);
output.Attributes.Add(ta);

6 Comments

FYI output.Attributes.Remove(existingClass); should be located inside the if statement, otherwise it's trying to remove a null value.
existingClass.Value.ToString() won't work because existingClass.Value is of type Microsoft.AspNetCore.Mvc.TagHelpers.TagHelperOutputExtensions.ClassAttributeHtmlContent class.
To be precise it will work if there is only one class name. But not for 2 or more, for example <div class="message text" ></div> won't return classes in ToString().
My example above with <div../> is not correct. Actually method .ToString() works fine if there were no tag-helpers which added some extra classes via output. Attributes.Add("class", ...) before our tag-helper is invoked. If they did then method .ToString() won't return expected names of css classes. It will return "ClassAttributeHtml‌​Content" C# class name instead in ASP.NET Core 2.
Boy oh boy is this UGLY that we have to do it this way. I will be writing an extension method to greatly alleviate this pain, but I wonder why the team can't see the Need for Simplicity® here.
|
2

The other answers here does not check current css class to avoid duplicate values. Here, I wrote an extension to add a css class with proper checks to ensure clean html at output:

public static class GeneralExtionsions
{
    //the white space chars valid as separators between every two css class names
    static readonly char[] spaceChars = new char[] { ' ', '\t', '\r', '\n', '\f' };

    /// <summary> Adds or updates the specified css class to list of classes of this TagHelperOutput.</summary>
    public static void AddCssClass(this TagHelperOutput output, string newClass)
    {
        //get current class value:
        string curClass = output.Attributes["class"]?.Value?.ToString(); //output.Attributes.FirstOrDefault(a => a.Name == "class")?.Value?.ToString();

        //check if newClass is null or equal to current class, nothing to do
        if (string.IsNullOrWhiteSpace(newClass) || string.Equals(curClass, newClass, StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        //append newClass to end of curClass if curClass is not null and does not already contain newClass:
        if (!string.IsNullOrWhiteSpace(curClass) 
            && curClass.Split(spaceChars, StringSplitOptions.RemoveEmptyEntries).Contains(newClass, StringComparer.OrdinalIgnoreCase)
            )
        {
            newClass = $"{curClass} {newClass}";
        }

        //set new css class value:
        output.Attributes.SetAttribute("class", newClass);

    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.