Use Arbitrary Parameters and Attribute Splatting in Blazor

In the previous article
we discussed how parameters can be passed to Blazor component. In the examples
discussed so far you created a fixed number of parameters (for example, Value
parameter of the Message component) and assigned them some value from the parent
component (Index.razor in our examples). What if you want to pass arbitrary
number of parameters to a component? That means you won't know the exact parameters
at development time. The parent component (Index.razor) will set arbitrary
parameters on a child component (Message.razor) when the child component is
used. This article explores how this can be accomplished. In the process you
will also learn about what is known as Attribute Splatting.
Let's get going!
Open the same Blazor Server project you created in the previous article.
Currently, the Message component contains just a single parameter Value:
[Parameter]
public string Value { get; set; }
Add one more parameter called ArbitraryAttributeDictionary as shown below:
[Parameter(CaptureUnmatchedValues =true)]
public Dictionary<string, object>
ArbitraryAttributeDictionary { get; set; }
Here, the ArbitraryAttributeDictionary property is a Dictionary. The keys of
the Dictionary will be strings whereas the values will be objects. The
ArbitraryAttributeDictionary property is decorated with [Parameter] attribute.
This time we also set the CaptureUnmatchedValues property of the Parameter
attribute to true. This indicates that any attributes set by the parent
component that do not have matching parameter properties in the child component
will be made available in the ArbitraryAttributeDictionary.
Before we actually use the arbitrary attributes passed in the
ArbitraryAttributeDictionary, let's first see the usage syntax of the newly
added parameter.
Open Index.razor parent component and place the <Message> component like
this:
<Message id="div1"
class="divClass"
title="This is sample <DIV> element."
Value="Hello World!">
</Message>
Notice this markup carefully. It sets three attributes that do not have any
matching parameters - id, class, and title. It also sets the Value attribute
that maps to the Value paremeter.
So far so good.
Now that the parent is passing four parameters to the Message component,
let's put these parameters to use inside the Message component.
Go back to the Message.razor and place a <div> element as shown below:
<div @attributes="ArbitraryAttributeDictionary">
@Value
</div>
Here, the @attributes directive points to the ArbitraryAttributeDictionary
dictionary. It then adds the key-value pairs from the dictionary to the <div>
element. This is called
Attribute Splatting. So, at runtime the <div> element will look like this:
<div id="div1"
class="divClass"
title="This is sample <DIV> element.">
Hello World!
</div>
Where do we put the divClass CSS class? You can attach a component specific
CSS style sheet file and add the divClass there.
To do so, add a new Style Sheet named Message.razor.css

Because of this particular naming convention, it will appear nested in the
Solution Explorer.

Now add the following CSS class to the newly added style sheet.
.divClass {
border:5px solid red;
padding:5px;
background-color:yellow;
width:60%;
font-size:20px;
font-weight:bold;
}
Run the application and notice how the <div> is rendered on the page.

As you can see the <div> has correctly picked the class and title attribute
values.
It should be noted that attribute splatting can be used independently of
arbitrary attributes. For example, you can create a Dictionary parameter without
setting CaptureUnmatchedValues property and then set that parameter explicitly
from the parent component (like you did with the Value parameter).
Consider the following parameter added to the Message component.
[Parameter]
public Dictionary<string,object> AttributeDictionary
{ get; set; }
Here, AttributeDictionary is a normal parameter that stores key-value
Dictionary.
You can set this parameter from the Index.razor parent component as follows:
<Message AttributeDictionary="objDictionary"
Value="Hello World!">
</Message>
The AttributeDictionary attribute is set to a Dictionary object named
objDictionary containing required key-value pairs. The objDictionary gets
created in the Index.razor @code block:
@code{
Dictionary<string, object> objDictionary =
new Dictionary<string, object>()
{
{"id","div1" },
{"class","divClass" },
{"title","This is sample <DIV> element." }
};
}
The <div> element inside the Message component will now use
AttributeDictionary for attribute splatting.
<div @attributes="AttributeDictionary">
@Value
</div>
Run the application again. The outcome will be identical to the previous run
but this time we didn't use arbitrary parameters.
What will happen if the parent component doesn't set the AttributeDictionary
parameter? Obviously, the <div> won't have id, class, and title attributes at
all. You might want to set some default values for id, class, and title
attributes just in case the parent doesn't set the AttributeDictionary
parameter. This is how you can do that:
[Parameter]
public Dictionary<string, object> AttributeDictionary
{ get; set; } = new Dictionary<string, object>()
{
{"id","div100" },
{"class","divClass2" },
{"title","Sample Title" }
};
Here, we assigned some default values to AttributeDictionary property.
The divClass2 used above can be added to the Message.razor.css file:
.divClass2 {
border: 5px solid blue;
padding: 5px;
background-color: cyan;
width: 60%;
font-size: 20px;
font-weight: bold;
}
Open the Index.razor parent component and change the <Message> element like
this:
<Message Value="Hello World!">
</Message>
So, here we didn't set the AttributeDictionary attribute at all.
If you run the application now, you will get this output:

As you can see, the <div> has now picked up the default values for id, class,
and title attributes.
That's it for now! Keep coding!!