Repeated code
In my application, I had code like this that was repeated in a bunch of places:
@if (economy.Cash == economy_base.Cash)
{
<span>
"Cash" @(String.Format("{0:N2}", economy.Cash))
</span>
}
else
{
<span>
Cash @(String.Format("{0:N2}", economy_base.Cash))
<span style="color: purple;">
(@(String.Format("{0:N2}", economy.Cash)))
</span>
</span>
}
where economy.Cash
, economy_base.Cash
and "Cash"
were values that were different in each case.
Factoring it out into a function
At first, I looked into using the technique described here that works for ASP.NET Core applications:
https://stackoverflow.com/a/67656536/268581
However, the exact approach there didn't seem to work in Blazor.
So instead of using a function signature of async Task Template(...)
I used void Template(...)
. And this seems to have worked!
Given this:
@{
void Template(string label, decimal? a, decimal? b)
{
@if (a == b)
{
<span>
@label @(String.Format("{0:N2}", a))
</span>
}
else
{
<span>
@label @(String.Format("{0:N2}", b))
<span style="color: purple;">
(@(String.Format("{0:N2}", a)))
</span>
</span>
}
}
}
I can use the following:
@{
Template("Cash", economy.Cash, economy_base.Cash);
}
and it'll expand into the example code shown above in the first section.
Question
When defining Template
I just took a wild guess and tried the void Template(...)
signature.
My question is, is this a valid and recommended way to factor out Blazor markup into a function?
CodePudding user response:
My question is, is this a valid and recommended way to factor out Blazor markup into a function?
There is nothing inherently wrong with it, but be aware that this is not a normal Template.
What you have here is a local function inside the override BuildRenderTree()
that is generated from the markup section. Hence the need to surround the calls with @ { }
.
Your other options are
a
RenderFragment<T> Template
, but that would require that you bundlestring label, decimal? a, decimal? b
into one Type somehow.
Usage@Template(new MyType("Cash", economy.Cash, economy_base.Cash))
, without extra@{}
a normal Blazor Component (separate .razor file).
Usage would look like<Template Label="Cash" A="economy.Cash" B="economy_base.Cash" />
CodePudding user response:
My question is, is this a valid and recommended way to factor out Blazor markup into a function?
This may be a valid way to do that, but it is not the way things are done in Blazor. The recommanded way or rather a good practice is to use the RenderFragment delegate type, which was invented to render partial markup...
There are plenty of ways to implement your function... Here's one:
Copy and test...
@page "/"
@Template(("my label", valA, valB))
@code
{
decimal? valA = 2.34M;
decimal? valB = 3.34M;
private RenderFragment<(string label, decimal? a, decimal? b)> Template => value => __builder =>
{
@if (@value.a == @value.b)
{
<span>
@value.label @(String.Format("{0:N2}", @value.a))
</span>
}
else
{
<span>
@value.label @(String.Format("{0:N2}", @value.b))
<span style="color: purple;">
(@(String.Format("{0:N2}", @value.a)))
</span>
</span>
}
};
}
Note: It is a good practice to use the RenderFragment delegate in place of Rqazor components. Thus, and solution to implement your code through components is a very bad thing to do. Components are very expensive, and must not be used for the sole purpose of rendering content.