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:
You can download the example code used in this topic on GitHub.
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:
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:
To implement of the Generic Projection, you will need to:
@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.
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> }
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>
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:
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: