0

My end goal is to create a reusable mat-tab-group component that adds some functionality to be able to close all tabs. I have found a technique for doing this here:

https://stackoverflow.com/a/53818913/811277

My next set was to wrap the functionality so it can be turned into a re-usable component. I have tried using the technique found here:

Angular Material Tabs not working with wrapper component

In the end I'm having trouble creating an empty MatTab component to insert at the beginning my list of MatTabs.

I've created a StackBlitz for this:

https://stackblitz.com/edit/angular9-material-baseline-nns7wc

  public ngAfterViewInit() {
     const matTabsFromQueryList = this._allTabs.map((tab) => tab.matTab);
     const list = new QueryList<MatTab>();
     // Create & Prepend a new MatTab here?
     list.reset([matTabsFromQueryList]);
     this._tabBodyWrapper._tabs = list;
  }

I was hoping to just create a MatTab component in the code above, but it isn't as simple as just saying new MatTab();

Scott Dietrich
  • 686
  • 1
  • 8
  • 20

1 Answers1

0

I solved this by taking a deeper look at the code that was wrapping mat-tab-group. It was reading the children via @ContentChildren and attaching them to the _allTabs property. Therefore, my solution was to provide a <mat-tab> in the template and just make sure it was the first item in the list/query that gets assigned to _allTabs. Here is the full source for my solution:

import {
  Component,
  ContentChildren,
  QueryList,
  ViewChild,
  ViewContainerRef,
  ChangeDetectorRef,
} from '@angular/core';
import { MatTab, MatTabGroup } from '@angular/material/tabs';

import { UiTabExtendedComponent } from '../ui-tab-extended/ui-tab-extended.component';

@Component({
  selector: 'ui-tabs-extended',
  styleUrls: ['./ui-tabs-extended.component.scss'],
  template: `
    <div class="footer-tabs-flex">
      <div class="footer-tabs-flex-main">
        <mat-tab-group #_tabBodyWrapper class="footer-tabs">
          <mat-tab #_blankTab></mat-tab>
          <ng-content #outlet></ng-content>
        </mat-tab-group>
      </div>
      <div class="footer-tabs-flex-close">
        <mat-icon
          mat-list-icon
          fontSet="fal"
          fontIcon="fa-times"
          (click)="_tabBodyWrapper.selectedIndex = 0"
        ></mat-icon>
      </div>
    </div>
  `,
})
export class UiTabsExtendedComponent {
  @ViewChild(MatTabGroup)
  public _tabBodyWrapper: MatTabGroup;

  @ViewChild(MatTab)
  public _blankTab: MatTab;

  @ContentChildren(UiTabExtendedComponent)
  protected _allTabs: QueryList<UiTabExtendedComponent>;

  @ViewChild('outlet', { read: ViewContainerRef }) container;

  constructor(private cd: ChangeDetectorRef) {}

  public ngAfterViewInit() {
    const matTabsFromQueryList = this._allTabs.map((tab) => tab.matTab);
    matTabsFromQueryList.unshift(this._blankTab);
    const list = new QueryList<MatTab>();
    list.reset([matTabsFromQueryList]);
    this._tabBodyWrapper._allTabs = list;
    this._tabBodyWrapper.ngAfterContentInit();
    this.cd.detectChanges();
  }
}
::ng-deep .mat-tab-labels > .mat-tab-label:first-child {
  display: none;
}

.footer-tabs {
  width: 100%;
}

.footer-tabs-flex {
  display: flex;
  background-color: #dde1ec;
}

.footer-tabs-flex-main {
  flex: 1;
}

.footer-tabs-flex-close {
  flex-shrink: 0;
  margin-left: 16px;
  margin-top: 16px;

  mat-icon {
    cursor: pointer;
  }
}
Scott Dietrich
  • 686
  • 1
  • 8
  • 20