Home > Net >  Template Page For Blazor Component
Template Page For Blazor Component

Time:09-28

Basically I am trying to create a mix of a Templated Component and a layout. I want a page layout that I can reuse, and still pass required parameters to. I think a way to do this may be to take advantage of an abstract base class.

This could be solved by my third option if I wanted to do it all through render tree building, but I do not want to do that. I'm okay with the base being built by a render tree (i.e. Option 3), but not the component that inherits from it (i.e. MyGrid.razor)

What I want to do:

MyGrid.razor

@page "/mygrid"
@inherits GridPage @*or "layout" or whatever works*@

<Grid>
    <Column>
    <Column>
</Grid>

@code {
    protected overrides string Title => "My Grid"
}

GridPage.cs

<header>@Title</header>
<div>@ChildContent</div>

@code {
    [Parameter] public string Title { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }
}

Solutions I Have Tried

  1. Layout

GridLayout

<header>@Title</header>
<div>@Body</div>

@code {
    [CascadingParameter]
    [Parameter] public string Title { get; set; }
}

Issue is that you have to remember this param is available and it is not required to impliment

  1. Template
<GridPageTemplate Title="My Title">
    <Grid>
         <Column>
         <Column>
    </Grid>
</GridPageTemplate> 

Issue here is that I would have to wrap my component with the template (not that big of deal, but would rather inherit) and I still don't know which params are required to impliment.

  1. Abstract Base Class
public abstract class GridPage : ComponentBase
{
    protected abstract string Title { get; }
  
    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        builder.OpenRegion(0);
        builder.OpenElement(1, "header");
        builder.AddContent(2, Title);
        builder.CloseElement();
        builder.CloseRegion();

        builder.OpenElement(3, "div")
        builder.OpenRegion(10);
        this.BuildRenderTree(builder);
        builder.CloseRegion();
        builder.Closelement()
    }
}

Issue is this one doesn't seem to work. I actually thought it would cause it would just take in the component and continue the base render (this.BuildRenderTree(builder);).

Desired Outcome

Say you have two grids.. a Students grid and Classes grid. I would want a different grid (and title) for each of them. I want to customize the title and columns for each basically. They would have a common layout markup (what I call GridPage), but MyGrid (either Students or Classes) would be different.

Students.razor

@page "/students"
@inherits GridPage

<Grid RowType=Student>
    <Column For="StudentName">
    <Column For="StudentAge">
    <Column For="StudentHomeRoom">
</Grid>

@code {
    protected overrides string Title => "Students"
}

Classes.razor

@page "/classes"
@inherits GridPage

<Grid RowType=Class>
    <Column For="ClassName">
    <Column For="ClassTime">
</Grid>

@code {
    protected overrides string Title => "Classes"
}

They would both output

<header>Title_here</header>
<div>Grid_markup_here</div>

CodePudding user response:

Create the abstract base class with common properties required for logic and then extend it where you actually have to render.

AbstractBaseClass.razor.cs

public class AbstractBaseClass<T> : ComponentBase
{
    [Parameter]
    public string Title {get;set;}

    [Parameter]
    public T TypedObject {get;set;}

    [Parameter]
    public RenderFragment<T> TypedComponent {get;set;}
    
    [Parameter]
    public RenderFragment CommonUi {get;set;}

}

In one implementation:

IntType.razor

@inherits AbstractBaseClass<int>
@CommonUi
 // or any other markup logic if any    
@TypedComponent(TypedObject)

StringType.razor

@inherits AbstractBaseClass<string>
@CommonUi
 // or any other markup logic if any    
@TypedComponent(TypedObject)

Then use it with the hard implementation

<StringType TypedObject="StackOverflow" >
  <CommonUi> /* Component common to both*/ </CommonUi>
</StringType>

<IntType TypedObject="2" >
   <CommonUi> /* Component common to both*/ </CommonUi>
</IntType>

CodePudding user response:

Blazor offers a composition model. Your pages will still have to be routable components. Why not go with the flow:

MyGrid.razor

<GridPage Title="Title">
  <Grid>
      <Column>
      <Column>
  </Grid>
</GridPage>

@code {
    string Title => "My Grid"
}

You already have the GridPage template:

<header>@Title</header>
<div>@ChildContent</div>

@code {
    [Parameter] public string Title { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }
}

Your attempts to turn this inside-out will at least require a lot of effort.

CodePudding user response:

Component inheritance works for inheriting functionality, but not for content. As soon as you define some razor content BuildRenderTree gets overridden.

You need to think Components.

GridPage.razor is a component and looks like this:

<header>@Title</header>
<div>@ChildContent</div>

@code {
    [Parameter] public string Title { get; set; } = "Silly sod, you didn't define a header";
    [Parameter] public RenderFragment ChildContent { get; set; }
}

and then MyGrid.Razor is a RouteView.

@page "/MyGrid"
<GridPage Title="My Grid Page">
    <Column>
    <Column>
... more markup
</GridPage>

CodePudding user response:

Not sure what you want...Anyhow here's my input:

Warning:

  1. "As soon as you define some razor content BuildRenderTree gets overridden" ATTRIBUTION: MrC aka Shaun Curtis
  2. Avoid using unnecessary layers of components. It's very expensive and make your application slower.

I'm of the opinion that your design should be as follows:

A Grid component A Column component And perhaps GridLayout, which is really superfluous :

Here's how I would use the Data Grid on the Index page: Index.razor

<Grid>
  <Column />
  <Column />
</Grid>

You could, of course, do something like this:

GridLayout.razor

<Grid>
  <Column />
  <Column />
</Grid>

And in the Index page instantiate the GridLayout component like this:

Index.razor

<GridLayout />
  • Related