How to select NgbTabset tab as active on load?

29,922

Solution 1

I figured out how to get this to work, but I am undecided as to whether it is a kludgy workaround or an elegant solution.

I ended up going against the advice at https://ng-bootstrap.github.io/#/components/tabs/api, which said "Use the "select" method to switch a tab programmatically". I did use activeId, with the core code being:

<ngb-tabset [activeId]="activeIdString">

[activeId] binds to a variable activeIdString, not a method as I described in the original post (using a getActiveId() method instead of a variable results in the "Expression has changed after it was checked" error message, which although it is a development mode only error, as described at https://github.com/angular/angular/issues/6005, is still a problem.)

The variable activeIdString is set when the component initializes:

  ngOnInit(): void {
    this.activeIdString = this.tabNameString[this.personService.getNextTab()];
  }

Since this code is on the component with the tabs, I record mostRecentTab on this component and convert it to nextTab on the navigation component before reaching the component with tabs, getting rid of any need to pay attention to exactly when ngOnInit executes in relation to when I record mostRecentTab.

A discussion "Cannot programmatically select tab" at https://github.com/ng-bootstrap/ng-bootstrap/issues/1016 also suggests using activeId, so I feel some confidence in disregarding the advice on https://ng-bootstrap.github.io/#/components/tabs/api to "Use the "select" method to switch a tab programmatically".

Solution 2

Somehow those answers didnt work, so I found another solution. An easier one. I hope it helps someone. Just follow these steps:

1. Give your tabset a 'tabset' identifier:

<ngb-tabset #tabset="ngbTabset"> many tabs... </ngb-tabset>

2. Give every <tab> in your <tabset> an unique id

<ngb-tab id="tab1"> Tab 1 </ngb-tab>
<ngb-tab id="tab2"> Tab 2 </ngb-tab>
<ngb-tab id="tab3"> Tab 3 </ngb-tab>

3. Declare a @ViewChild for your tabset

@ViewChild('tabset')
tabset: any;

4. Set active tab inside ngAfterViewInit (not ngOnInit, that's too early!)

this.tabset.select('tab3');

Works perfectly for me. Sorry for strange formatting, Stack Overflow doesnt work properly sometimes.

Solution 3

I've just accomplished this exact thing with the ngb-accordian.

The accordion looks like this:

<ngb-accordion #acc="ngbAccordion" activeIds="ngb-panel-0" [closeOthers]="true">

  <ngb-panel id="static-1" title="First panel">
    <ng-template ngbPanelTitle>
        <button type="button" class="btn" data-toggle="button">
               Tab One
         </button>
    </ng-template>
    <ng-template ngbPanelContent>
         Tab One Content
    </ng-template>
  </ngb-panel>

  <ngb-panel id="static-2" title="Second">
    <ng-template ngbPanelTitle>
        <button type="button" class="btn" data-toggle="button">
              Tab Two
         </button>
    </ng-template>
    <ng-template ngbPanelContent>
         Tab Two Content
    </ng-template>
  </ngb-panel>

</ngb-accordion>

I set the tab I want displayed in a State Service (stateSvc) as an Observable, and then subscribe to it in my component, so when I'm navigating away from a form and want to return to the users-manage tab for example, I set stateSrv.this.currentAccordianTab = 'users-manage' and then navigate to the component with the accordian.

@ViewChild gives me a reference to the ngb-accordian in the template by its template reference (#acc)

In my class, I have this:

@ViewChild('acc') acc;

currentAccordianTab: string;

ngAfterContentInit() {
    this.stateSvc.currentTab$
        .subscribe(response => {
            this.currentAccordianTab = response;
            if (this.currentAccordianTab = 'users-manage') {
                this.acc.toggle('static-2');
            } else {
                this.acc.toggle('static-1');
            }
        });
}

On the ngb-accordian, there's a toggle method that takes a tab-id parameter to set the current tab. I'm guessing the select method is the equivalent on the ngb-tabset, but you can check the API doc.

Basically we're getting a reference to the ngb-accordian with @ViewChild, and then calling its toggle function this.acc.toggle('static-2'); to set the state to the correctly visible tab.

Solution 4

According to docs, you need to use select method. To do that, first add identificator for tabset in your view html file:

<ngb-tabset #tabset="ngbTabset">

In your .ts file declare your ViewChild:

@ViewChild('tabset') tabset;

And then just use method this way:

this.tabset.select(YOUR_TAB_ID_HERE);

PS: Althought @Mickey Segal solution may work in most cases, in my projects i saw, that sometimes it doesn't work, so i suggest to use documented way of changing active tab.

Share:
29,922

Related videos on Youtube

Mickey Segal
Author by

Mickey Segal

Updated on March 03, 2021

Comments

  • Mickey Segal
    Mickey Segal about 3 years

    The "Select an active tab by id" example at https://ng-bootstrap.github.io/#/components/tabs shows how to use a DOM button to programmatically select an Angular Bootstrap tab to be active. But how do you set a tab to be active from within the TypeScript code - for example by referencing some persistent state of what tab was most recently open on this view using a service that stored the state?

    The activeId documentation on that page explains how to hard-code a tab to be active, but I need to set the tab choice programmatically. I can set the tab using [activeId] = getActiveId() (where getActiveId() accesses a service in which I can store the tab value), but that gets into all sorts of issues with when the activeId is set, which is presumably why the documentation says "Use the "select" method to switch a tab programmatically".

    Following this direction I tried using select on the ngb-tabset and using the html onload event to solve this in the DOM, but was unclear where to place onload and I couldn't get this to work.

    I tried using ngOnInit in the TypeScript to set the DOM state but couldn't figure out how to refer to the ngb-tabset.

    What is a good way to coordinate between the TypeScript and the DOM to select NgbTabset tab as active on load?

Related