Wilhelm Olejnik
Wilhelm Olejnik

Reputation: 2507

Angular Material table with subrows (nested cells) of different heights

I would like to create a table with nested cells imitating subrows. It works fine if content of every cell does not exceed min-height property value of nested cell (A).

Unfortunately when this value is exceeded the table breaks down (B). Is there any simple* way to align nested cells properly to obtain table like (C)?

code: https://stackblitz.com/edit/angular-aejwfm

img

(*) I know that we can use javascript to set height of all cells representing certain subrow to max(heights of all cells from that subrow) but I would prefer pure HTML/CSS/Angular solution.

Upvotes: 1

Views: 12402

Answers (1)

HirenParekh
HirenParekh

Reputation: 3735

One possible solution is you can create one directive that finds a cell with max-height for each row and apply the same height to all the cell of that row.

But you are rendering data column vise so you need to provide some information to the directive using which the directive can identify cells of a single row.

I have updated your code to achieve the desired result.

https://stackblitz.com/edit/angular-aejwfm-6htvuk

here is the brief explanation of the changes I have done to your demo:

create one directive which accepts the book object as Input. This book object will help us to identify cells of single row.

@Directive({
  selector: '[matchCellHeight]'
})
export class MatchCellHeightDirective {

  @Input() matchCellHeight: any;

  constructor(private el: ElementRef) { 

  }
}

then bind this directive to each cell element in your template.

    <ng-container matColumnDef="title">
      <mat-header-cell *matHeaderCellDef> Title </mat-header-cell>
      <mat-cell *matCellDef="let genre">
        <mat-cell [matchCellHeight]='book' *ngFor="let book of genre.books"> //bind matchCellHeight to each cell
           {{book.title}} 
        </mat-cell>
      </mat-cell>
    </ng-container>

    <ng-container matColumnDef="pages">
      <mat-header-cell *matHeaderCellDef> Pages </mat-header-cell>
      <mat-cell *matCellDef="let genre">
        <mat-cell [matchCellHeight]='book' *ngFor="let book of genre.books">
           {{book.pages}} 
        </mat-cell>
      </mat-cell>
    </ng-container>

Now we need to store reference of each cell somewhere so that we can apply our match height logic on each cell. for that I have created one service and injected it in the directive.

@Injectable()
export class MatchCellHeightService{
  cells:{el:ElementRef,data:any}[] = [];
  constructor(){

  }

  findUniqueBooks():any[]{
    return this.cells.map(currCell => currCell.data).reduce(
      (acc,curr) => {
        if(acc){
          if(acc.indexOf(curr) == -1){
            acc.push(curr);
          }
        }else{
          acc = [].push(curr)
        }
        return acc;
      },[]
    )
  }

  matchHeight(){
    /* first find all the unique books*/
    let books = this.findUniqueBooks();


    for(let i = 0; i < books.length ; i++){
      let currbook = books[i];

      /*for each book find cells that containins this book object info
        (in this demo each row is containng info about one book there for we are using book object 
        to identify cells of each row)
      */
      let bookCells:{el:ElementRef,data:any}[] = [];

        for(let j = 0; j < this.cells.length ; j++){
          let currCell = this.cells[j];
          if(currCell.data == currbook){
            bookCells.push(currCell);
          }
        }

        /*once we have the array of cells which are of same row apply the match height logic*/
        bookCells.forEach(val => val.el.nativeElement.style.height = 'initial');
        let maxHeight = Math.max(...bookCells.map(val => val.el.nativeElement.offsetHeight));
        bookCells.forEach(currCell => {
          currCell.el.nativeElement.style.height = maxHeight+'px';
        })
    }
  }
}

I hope this will help. And I have also found another implementation of a directive that does the same job. Here is the link for that. https://scotch.io/tutorials/responsive-equal-height-with-angular-directive

Upvotes: 6

Related Questions