3

I need to get the value of whatever tab the user clicks on. Here's what I have so far:

<mat-tab-group (selectedTabChange)="getLabel($event)" #tabGroup>
    <mat-tab label="{{ thing.name }}" *ngFor="let thing of things | async" #tab>
        ....
    </mat-tab>
</mat-tab-group>

TS - Database Fetch:

thingsCollection: AngularFirestoreCollection<Intf>;
things: Observable<Intf[]>;

ngOnInit() {
    this.thingsCollection = this.afs.collection(placeToSearch2);
    this.things = this.thingsCollection.valueChanges();
}

The issue is that I also need the value of the label property of the tab that the mat-tab-group first loads. (selectedTabChange) only fires when the user manually clicks on a tab. That's good, but doesn't give me the label of the first tab.

There was a similar question here with a good answer, but the commenter seemed to ghost on me when I asked him my particular question more clearly. The answer that he provided was close to what I need:

ngAfterViewInit() {
    console.log('afterViewInit => ', this.tabGroup.selectedIndex); // Close, but no cigar
  }

The above solution only gives me the index (which is almost always 0), not the label. How can I get the label? The Angular Tab reference shows there is a textLabel property. I think this might be the answer, but it uses @Input which I'm not familiar with. Can someone please help me use it?

FiringBlanks
  • 1,998
  • 4
  • 32
  • 48

2 Answers2

3

You can get it using the following:

this.tabGroup._tabs.first.textLabel

See this StackBlitz demo.

FAISAL
  • 33,618
  • 10
  • 97
  • 105
  • Small problem actually. The ngAfterViewInit() function fires before any information comes back from the database, so it fires before there is any tab to retrieve the label information from. So if I don't have any other static tabs, it will give me an error: 'Cannot read property 'textLabel' of undefined'. – FiringBlanks Oct 23 '17 at 07:21
  • There are two ways then, 1) Get the label after the data is loaded, 2) Use the safe navigation operator `this.tabGroup?._tabs?.first?.textLabel` – FAISAL Oct 23 '17 at 07:24
  • Using the safe navigation operators gives me [this](https://imgur.com/a/AzTiB) error. How can I wait for the tab to finish loading it's data? – FiringBlanks Oct 23 '17 at 07:31
  • I am not sure what data type you have for `things`, since it is async, you will have to subscribe for changes and then get the first tab label. – FAISAL Oct 23 '17 at 07:42
  • It's an observable. I updated the code again. I think it's what you're looking for. – FiringBlanks Oct 23 '17 at 07:50
  • then you can do something like: `this.things.subscribe( ()=> { let label = this.tabGroup._tabs.first.textLabel; });` ... try something like this – FAISAL Oct 23 '17 at 07:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/157263/discussion-between-firingblanks-and-faisal). – FiringBlanks Oct 23 '17 at 08:50
1

You should always stick to public apis as much as possible instead of depending on the core implementation because in the future if they change the internals your app will break. You can change your component to look like, add

  @ViewChildren(MatTab) tabs: QueryList<MatTab>;

This will query all your tabs and make a query list.

and then in the on init, when your data arrives you should check for the first tab. So in your component you can just do,

  ngOnInit() {
      this.thingsCollection = this.afs.collection(placeToSearch2);
      this.things = this.thingsCollection.valueChanges();
      this.things.finally(() => {
          setTimeout(() => { this.checkSelection(); });
      });
  }

  checkSelection() {
    let tab = this.tabs.first;
    console.log('selected tab', tab);
  }

This will query the list and will give you the first tab.

Anik
  • 2,692
  • 2
  • 22
  • 25
  • This is already implemented by the OP. The obvious problem is that he is unable to get tab label when the content load. The other case is working fine. Unfortunately, your solution does not solve the problem – FAISAL Oct 23 '17 at 07:26
  • It says "Property finally does not exist on type Observable" – FiringBlanks Oct 23 '17 at 08:09
  • https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/finally.md So you proably need to do `import 'rxjs/Observable/finally'` – Anik Oct 23 '17 at 08:13
  • it says 'cannot find module rxjs/Observable/finally' – FiringBlanks Oct 23 '17 at 08:20
  • importing 'finally' worked with 'import rxjs/add/operator/finally'; but still the same problem. The tabs aren't ready when the checking starts. I need a way to wait for the data. – FiringBlanks Oct 23 '17 at 08:50
  • https://stackblitz.com/edit/angular-material2-issue-x8w5cr In this stackblitz i have created an example for you with a dmeo data service where you can see, how we can grab the tab's text after your data is received after 3 secons. – Anik Oct 23 '17 at 09:02
  • Waiting 3 seconds is not a good idea. Would it be possible to attach a callback that would fire after the ngFor is done loading the tabs? – FiringBlanks Oct 23 '17 at 10:55
  • you didnt understand, waiting 3 seconds is just for demo to mimic the delay of your server response Only thing i did is add a setTimeout() after you receive data to miss a frame so that angular is done rendering the tabs :) – Anik Oct 23 '17 at 13:23