Pass Data To All Descendents With CascadingParameter In Blazor

Introduction

Let's first understand the problem, then we will also understand the solution and only then we will solve the problem with the solution! 

The Problem

Have you ever come across a situation where you want to cascade some data from parent to its grandchild? Well there is one workaround and you already know the drill. Have a look at the following image 1, see if this rings the bell.


Image 1: Parent is sending message to Child and GandChild with "component [Parameter]"

The Situation in Image 1: Parent wants to communicate with its GranChild, but there is no direct way. Workaround allows it to communicate with its own child and then that child will go and talk with GrandChild. So level by level.

Explanation of Image 1: Parent is sending message, "Hi from Parent!" to its child, Then child component sending that message to the grandchild component.

So how do I come out of this workaround?

The solution

There is a way, and it's called  "CascadingParameter". Let's first understand how it works under the carpet.

In the following image 2, The Parent can directly communicate with all of its descendants directly just by using CascadingParameter, which means now grandparent can give chocolate directly to their grandchild without their parent eating half of it. 

In nutshell, CascadingParameter cuts down the dependence of layers to pass down the data. Isn't this beautiful?


Image 2: Parent is sending message to all descends with [CascadingParameter]

So what is the advantage?

You don't have to pass data from every parent to its child, that means while creating a child component's instance we don't actually need to pass the data. Only parents will pass the data; this will make the UI neat and clean.

Rule

Name of the CascadingParameter really doesn't matter, what matters is type of the parameter. For eg. If the parent is sending a string parameter then the child should have a CascadingParameter which is a string type where the child can give any name to its  CascadingParameter, parent couldn't care less. 

Okay finally let's get into real fun, The code.

In following listing 1, at line number 13 we are creating a message which is of type string which we need to cascade down to all descendants, at line number 4 we are creating an instance of a child component and we are not passing any parameter through child. Instead we are wrapping child component's instance in "CascadingValue", and this is the tag which is responsible to pass the data down the line, all we have to do is to bind the property that we created in line number 13 to the Value attribute of "CascadingValue" at line number 3.

@page "/Parent"
<h5 class="box" style="width:450px;padding:5px;">Parent</h5>
<CascadingValue Value="@Message">
    <Child></Child>
</CascadingValue>
<style>
    .box {
        background-color: rgb(224, 206, 247);
        border: 5px solid rebeccapurple;
    }
</style>
@code {
    public string Message { get; set; } = "Hi from Parent!";
}

Listing 1: Parent.razor

Next, Child.razor. Well well well, something is unusual going on in this child component. In line number 18, I am creating a CascadingParameter rather than normal Parameter, this is the property where parent component is going to assign the value, now all we have to do is it show it on the UI, for that check out line number 6. And to maintain a hierarchy we are creating a GrandChild component's instance at line number 5.

<div class="boxChild">
    <h5 class="m-1">Child</h5>
    <h6>@Message</h6>
</div>
    <GrandChild></GrandChild>
<style>
    .boxChild {
        background-color: #B7E5DD;
        border: 5px solid #123524;
        width: 400px;
        margin-left: 30px;
        margin-bottom: 10px;
        padding: 5px;
    }
</style>
@code {
    [CascadingParameter]
    public string Message { get; set; }
}

Listing 2: Child.razor

In GrandChild.razor we are having the same structure as Child.razor EXCEPT the name of the parameter at line number 18. We are changing the name from "Message" to "MessageDifferentName". This has been done purposefully to validate our rule that names don't matter, only type does. So technically this should work.

<div class="boxGrandChild">
    <h5 class="m-1">GrandChild</h5>
    <h6>@MessageDifferentName</h6>   
</div>
<GreatGrandChild></GreatGrandChild>
<style>
    .boxGrandChild {
        background-color: #B4C6A6;
        border: 5px solid #293462;
        width: 360px;
        margin-left: 50px;
        margin-bottom: 10px;
        padding: 5px;
    }
</style>
@code {
    [CascadingParameter]
    public string MessageDifferentName { get; set; }
}

Listing 3: GrandChild.razor

In the GreatGrandChild, we are changing the type of CascadingParameter, to validate our rule, type matters!! Parent looks for the same type that it passes on to its descendants. So this should fail and rather than showing the message "Hi from Parent!" it will print "0" the default-value of int.

Note
It doesn't give a runtime error if type mismatched it just prints the default value of mismatched type.

<div class="boxGreatGrandChild">
    <h5 class="m-1">Great GrandChild</h5>
    <h6>@Message</h6>
</div>
<style>
    .boxGreatGrandChild {
        background-color: #F9CEEE;
        border: 5px solid #9A0680;
        width: 330px;
        margin-left: 60px;
        margin-bottom: 10px;
        padding: 5px;
    }
</style>
@code {
    [CascadingParameter]
    public int Message { get; set; }
}

Listing 4: GreatGrandChild.razor

Now let's run this bad boy!!


Image 3: Output of listing 1,2,3,4.

Explanation of image 3: Our hierarchy of components is like this Parent -> Child -> GrandChild -> GreatGrandChild,

  1. Parent is printing no message
  2. Child  is printing the message that it received from parent in CascadingParameter (Same type, same name)
  3. GrandChild  is printing the message that it received from parent in CascadingParameter (Same type, different name)
  4. GreatGrandChild  is NOT printing the message that it received from parent instead its printing "0" that is default of its CascadingParameter's type int (Different type, same name)

Conclusion

And this is how you make use of CascadingParameter, it is very important not to leave any stone unturned when understanding the concepts. That's why it is very important to know what rules are there.
We not only saw what rules are there but we validated them with examples. Now we know what is acceptable and what you need to avoid while using CascadingParameter, this will stick to your brain how your bugs sticks to our code. 

Hit me up @ Linkedin