DEV Community

jsakamoto
jsakamoto

Posted on

Build CSS class string dynamically, based on boolean switch values, in Blazor App.

Building CSS class string in Angular app.

When I'm coding Angular SPA program, I can write a code to control CSS class string, like this.

// my.component.ts
@Component({template:'my.component.html',...})
export class MyComponent {
  rotate: boolean;
  disabled: boolean;
  ...
<!-- my.component.html -->
<div [ngClass]="{'rotate':rotate, 'disabled':disabled}">...

The above code will render DOM like this, depends on the condition of rotate and disabled properties of the component are true or not.

<div class="rotate disabled">...

This Angular's ngClass directive is intuitive and straightforward, I think.

The Blazor way is a little bit pain...

By the way, when I'm coding Blazor C# SPA program, controlling the CSS class string is a little bit painful.

I had to write a code that judge conditions and concatenate CSS class strings myself, instead of like Angular's way.

@* MyComponent.razor *@
<div class="@CssClass()">...

@code {
  bool Rotate;
  bool Disabled;

  // Should I implement a code like this everytime 
  // when I need to build CSS class string? Help me!
  string CssClass() {
    var cssClass = new List<string>();
    if (this.Rotate) cssClass.Add("rotate");
    if (this.Disabled) cssClass.Add("disabled");
    return string.Join(' ', cssClass);
  }
  ...

I couldn't be satisfied above solution.

What can I do?

Basic concept

Therefore, I decided to create a utility function to build CSS class string from anonymous type object, like Angular's way.

The basic concept of the utility function is:

  1. The function can be passed an anonymous object.
  2. The function picks up the bool properties of the object in argument by .NET CLR "Reflection" feature.
  3. The function filter those properties in which it's value is true.
  4. Finally, the function returns a string that is concatenated those properties name with space separator.

I implemented this concept in my class library.

I named the class CssClassInlineBuilder, and I named the function CssClass() as a static method.

The source code of CssClass() static method is like this:

// CssClassInlineBuilder.cs
public static class CssClassInlineBuilder 
{
  public static string CssClass(object obj)
  {
    var boolPropNames = obj.GetType()
      // Enumarate all properties of the argument object.
      .GetProperties()
      // Filter the properties only it's type is "bool".
      .Where(p => p.PropertyType == typeof(bool))
      // Filter the properties only that value is "true".
      .Where(p => (bool)p.GetMethod().Invoke(obj, null))
      // Collect names of properties, and convert it to lower case.
      .Selec(p => p.Name.ToLower());

    // Concatenate names of filtered properties with space separator.
    return string.Join(' ', boolPropNames);
  }
}

This class library allows me to write a code that building CSS class string dynamically without code snippets, like Angular's way.

@* MyComponent.razor *@
<div class="@CssClassInlineBuilder.CssClass(new {Rotate, Disabled})">...

@code {
  bool Rotate;
  bool Disabled;
  ...

That's great ;)

...However, I couldn't still satisfied with this code.

Don't you feel CssClassInlineBuilder.CssClass(new {...}) is very very too long?

Be more simplify!

One of the C# syntax helped me!

I used using static directive to omit the class name.

@* _Imports.razor *@
...
@using static CssClassInlineBuilder

Finally, I could write it only with method name!

@* MyComponent.razor *@
<div class="@CssClass(new {Rotate, Disabled})">...

@code {
  bool Rotate;
  bool Disabled;
  ...

Yey! :)
(Source code is on GitHub, inspired by "sushi-go-round".)

fig2

Conclusion

I brushed up this implementation, and I make this class library to be public as a NuGet package.

Please visit nuget.org if you are interested in this library.

fig1

You can find more detail of this my work on GitHub.


Happy coding with Blazor :)

Top comments (2)

Collapse
 
benmakesgames profile image
Ben Hendel-Doying

nice tutorial! I also have an Angular background, and miss some of its features when working in Blazor!

Collapse
 
jlopez788 profile image
Juan Lopez

This is the one feature I implemented a long ti. E ago when started dealing with blazor. Missed this feature from angular