Generic Projection

Content Projection is about generic UI, Generic Projection extends the Content Projection furthermore, it is about generic UI and generic data that associated with the UI. Generic Projection will hide some logic such as looping, if-else, ... In this tutorial:

  • Understand Generic Projection.
  • Understand the data flow in Generic Projection.
  • Implementing the Generic Projection technique.
  • The advantages of Generic Projection.
You can download the example code used in this topic on GitHub.

Understand Generic Projection

Without Generic Projection, all logic assembly in one component. Furthermore, that component is not reusable in terms of UI because that component itself define what the UI will look like.

With Generic Projection, you will be able to separate the common logic like if-else, looping in the generic projection component. Also, the generic projection component itself will not define what the UI will look like, but the user of that component will. The following image illustrates the advantage of Generic Projection compared to not using it:

without-generic-projection.png

with-generic-projection.png


Understand the data flow in Generic Projection

The generic projection component user (let's call it Component1) can pass data to the generic projection component (let's call it GenericProjectionComponent1) by Parameter. After the GenericProjectionComponent1 have processed the input data to output data, the GenericProjectionComponent1 will omit the output data to the Component1 by Context. The Component1 will receive the Context and then use it within the projecting content. The following image illustrate the data flow of the Generic Projection technique:

data-flow.png


Implementing the Generic Projection technique

To implement of the Generic Projection, you will need to:

  1. Define the generic projection component.
  2. Pass and retrieve data.

Define the generic projection component

  1. Create a new component (let's call it GenericProjectionChild).
  2. Declare projecting slots and the input data in the code section. For example:
@code {
    [Parameter]
    public RenderFragment<Cat>? CatTemplate { get; set; }

    [Parameter]
    public RenderFragment<Dog>? DogTemplate { get; set; }

    [Parameter]
    public RenderFragment<Bird>? BirdTemplate { get; set; }

    [Parameter]
    public List<IAnimal> InputData { get; set; } = new();
}

Instead of the RenderFragment for declaring a projecting slot as with the Content Projection technique, the Generic Projection technique use the generic version RenderFragment<T>, the T is the data that associates with the projecting slot.

  1. Perform logic (optional) and render the projecting slots with the Invoke(T) method in the UI section. For example:
@foreach (var animal in InputData)
{
    <div>
        @if (animal is Cat cat)
        {
            @CatTemplate?.Invoke(cat)
        }

        @if (animal is Dog dog)
        {
            @DogTemplate?.Invoke(dog)
        }

        @if (animal is Bird bird)
        {
            @BirdTemplate?.Invoke(bird)
        }
    </div>
}

Pass and retrieve data

As for the example, you can pass data to the GenericProjectionChild by using the InputData. To retrieve the output data from the GenericProjectionChild component, you can declare a variable in the Context keyword. For example:

<GenericProjectionChild InputData="Animals" Context="OutputFromProjection">
    <DogTemplate>
        <div>My name is @OutputFromProjection.Name, I am a dog.</div>
    </DogTemplate>
    <CatTemplate>
        <div>My name is @OutputFromProjection.Name, I am a cat.</div>
    </CatTemplate>
    <BirdTemplate>
        <div>My name is @OutputFromProjection.Name, I am a bird.</div>
    </BirdTemplate>
</GenericProjectionChild>

The result

With the Animals property is defined as follows:

@code {
    public List<IAnimal> Animals { get; set; } = new()
    {
        new Dog() { Name = "Doggy" },
        new Cat() { Name = "Pussy" },
        new Bird() { Name = "Birb" },
        new Cat() { Name = "Kitty" },
    };
}

Will give the following result:

the-result.png


The advantages of Generic Projection

As we mentioned at the beginning of this tutorial, the Generic Projection technique help you hide the logic in the high level and also defer the UI to the component user. In this section, we will compare the code without Generic Projection and the code with Generic Projection so you can have a closer look at its advantages.

Code without the Generic Projection:

@foreach(var animal in Animals)
{
    @if(animal is Dog)
    {
        <div>My name is @animal.Name, I am a dog.</div>
    }

    @if(animal is Cat)
    {
        <div>My name is @animal.Name, I am a cat.</div>
    }
        
    @if(animal is Bird)
    {
        <div>My name is @animal.Name, I am a bird.</div>
    }
}

Code with the Generic Projection:

<GenericProjectionChild InputData="Animals" Context="OutputFromProjection">
    <DogTemplate>
        <div>My name is @OutputFromProjection.Name, I am a dog.</div>
    </DogTemplate>
    <CatTemplate>
        <div>My name is @OutputFromProjection.Name, I am a cat.</div>
    </CatTemplate>
    <BirdTemplate>
        <div>My name is @OutputFromProjection.Name, I am a bird.</div>
    </BirdTemplate>
</GenericProjectionChild>

In summaries, the Generic Projection technique help you to create a high level component with the following advantages:

  • Separation of concern.
  • Reusable component.
  • Easier to extend and maintain the website.
BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2025 Blazor School
An unhandled error has occurred. Reload 🗙