how to access matTabNavBar.updateActiveLink method

Viewed 2498

MatTabNav Docs show a method that can be used to update the active links for a mat-tab-nav. No examples of how to implement this seem to exist and the source code does not give any better insight into how to implement.

Here is the html from my template:

<nav mat-tab-nav-bar #tabs>
  <a mat-tab-link *ngFor="let link of links"
    (click)="activelink = link.identifier"
    [active]="activelink === link.identifier"
    [routerLink]="[ './', link.identifier ]"
  >{{ link.title }}</a>
</nav>

I have attempted to access the method using the following two examples, however neither one seems to allow me to access the updateActiveLink method on this.tabs.

Failed attempt 1

@ViewChild( 'tabs' ) tabs: MatTabNav;

And failed attempt 2

@ViewChild( 'MatTabNav' ) tabs: MatTabNav;

What is confusing is that it it shows I need to pass a reference to the element to the item this.something.updateActiveLink( this.tabs ) so I attempted to import MatTabNav in the custructor and access it like so _matTabNav.updateActiveLink( this.tabs )

constructor(
  private _matTabNav: MatTabNav,
) { }

My End goal

I intend to highlight the first of the links when the route does not contain my tab. Also when the route is changed, I would like the tabs to reflect this change. So the first line will end up selecting the same

/route/
/route/tab1
/route/tab2
/route/tab3

And my routes which are both routing to the same component

{ component: MyTabComponent,       path: 'route/'     },
{ component: MyTabComponent,       path: 'route/:tab' },
2 Answers

You can get the MatTabNav and the MatTabLink elements by using @ViewCild and @ViewChildren queries by querying by the classes instead of names like that:

@ViewChild(MatTabNav) matTabNav: MatTabNav;
@ViewChildren(MatTabLink) linkElements: QueryList<MatTabLink>;

To change the selection from code you need then to set active false on the currently selected link and to true on the one you are selecting. After that call the method updateActiveLink. The ElementRef to pass is the element ref of the newly selected MatTabLink. Here is an example method that selects the second link for demonstration:

selectSecondLink() {
  const matTabLinks: MatTabLink[] = this.linkElements.toArray()
  matTabLinks[0].active = false;
  matTabLinks[1].active = true;
  this.matTabNav.updateActiveLink(matTabLinks[1]._elementRef);
}

Here is also a link to a working sample in StackBlitz.

For all this to work you will also need to remove the binding on the [active]. If you use the binding then there is no need to do all this things you just set the activeLink property to the link identifier you want to select and it will update automatically. For example like this:

changeSelection() {
  this.activeLink = this.links[1].identifier;
}

Here is a link to a sample that does this. You cannot mix both approaches because the binding will override what you do from code.

Not sure if this will be helpful as I don't have a stackblitz example with routes setup to test it further, but this is how I accessed the method using the tab nav bar example here tab-nav-bar-basic-example.ts


The method is accessed via the mat-tab-nav-bar like below.

Add templateRef

<nav #navBar mat-tab-nav-bar [backgroundColor]="background">

Then setup ViewChild using ref

@ViewChild('navBar') _navBar:any

Then console.log(this._navBar.updateActiveLink); results in the following output.

ƒ (element) {
        // Note: keeping the `element` for backwards-compat, but isn't being used for anything.
        // @breaking-change 8.0.0
        this._activeLinkChanged = !!element;
        this…

From here I suspect you would need to pass an elementRef of the mat-tab-link as this method in the source appears to update the private variable _activeLinkChanged and fire off change detection.

Looking elsewhere in the source seems this variable will do things like align the inkbar to the tab that the active link has changed for... because I do not have a setup stackblitz, I am not able to verify any of this part for you and analysis is based completely on source code review... hopefully some of this analysis will be helpful.

/** Checks if the active link has been changed and, if so, will update the ink bar. */
  ngAfterContentChecked(): void {
    if (this._activeLinkChanged) {
      const activeTab = this._tabLinks.find(tab => tab.active);

      this._activeLinkElement = activeTab ? activeTab._elementRef : null;
      this._alignInkBar();
      this._activeLinkChanged = false;
    }
  }
Related