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:
- The function can be passed an anonymous object.
- The function picks up the
bool
properties of the object in argument by .NET CLR "Reflection" feature. - The function filter those properties in which it's value is
true
. - 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".)
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.
You can find more detail of this my work on GitHub.
Happy coding with Blazor :)
Top comments (2)
nice tutorial! I also have an Angular background, and miss some of its features when working in Blazor!
This is the one feature I implemented a long ti. E ago when started dealing with blazor. Missed this feature from angular