How can I add a specific css class only to the last Blazor component created dynamically without using JS Interop

63 views Asked by At

I have a couple of simple components that can be structured like a table. Where I want to add borders on a property set to true. The problem I have is that I somehow have to find the last component(such as the last col - right most) and add the right border to it. Here are the components -

HeaderRow.razor

<div class="@(isBordered?"bordered":string.Empty)">
    @ChildContent
</div>
@code {
    [property]
    public bool Bordered{get{...} set{...}}
}

HeaderRow.razor.css

.bordered{
    border-top: solid 0.1em #707070;
    /*border-right: solid 0.1em #707070;*/
    border-bottom: solid 0.1em #707070;
}

HeaderCell.razor

<div>
    @ChildContent
</div>

ClientApp1.razor

<HeaderRow>
   <HeaderCell>Col 1</HeaderCell>
   <HeaderCell>Col 2</HeaderCell>
   <HeaderCell>Col 3</HeaderCell>
</HeaderRow>

ClientApp2.razor

<HeaderRow Bordered>
   <HeaderCell>Col 1</HeaderCell>
   <HeaderCell>Col 2</HeaderCell>
   <HeaderCell>Col 3</HeaderCell> // last HeaderCell
</HeaderRow>

The cells are added by hand or generated from a loop.

Now in the ClientApp2.razor, it has the property Bordered which indicates that the structure mush have borders including the child components HeaderCell. I might be able to add borders to the each HeaderCell using css such as

HeaderCell.razor.css

.bordered > div{
    border-left: solid 0.1em #707070;
}

.border-right{
    border-right: solid 0.1em #707070;
}

But from the above css the classes border-right would only go to the last cell and not others. So how can I find the last HeaderCell and add the appropriate css class to it.

I understand that border-right to the bordered class would solve the problem. however as I have come across it just wanted to know if there is a way with C# to do it.

Also JS Interop can be used but as it only works in OnAfterRender. It displays slight delay while adding the last borders. Which is noticeable.

1

There are 1 answers

0
Henk Holterman On BEST ANSWER

In order to do this you will need to do some bookkeeping. A simple approach is to publish the HeaderRow as a Cascading value:

<CascadingValue Value="this" IsFixed="true">
  <div class="@(isBordered?"bordered":string.Empty)">
    @ChildContent
  </div>
</CascadingValue> 

and then the HeaderCells can check themselves in:

<div>
    @ChildContent
</div>

@code {
  [CascadingParameter]
  public HeaderRow Parent { get; set; } = default!;

  bool Last => Parent.IsLast(this);

  override void OnInitialized() 
  {
     Parent.AddCell(this);
  }

}

It is now a simple programming task of tracking the last and maybe also the first or even all HeaderCells with AddCell() and related logic.

It depends on what you need but for example:

  public void AddCell(HeaderCell newCell)
  {
     _firstCell = _firstCell ?? newCell;
     _lastCell = newCell;
  }