ngx-bootstrap icon indicating copy to clipboard operation
ngx-bootstrap copied to clipboard

fix(tabs): order not working with ngIf\dynamic directives

Open yasemincidem opened this issue 8 years ago • 30 comments

I have been using tab directive.Additionally i used ngIf directive inside tab selector.Everything is right.But tab order not regular.It is not order as I want .Here my code:

<tabset [justified]="true">
  <tab (select)="showCustomer()" *ngIf="isRoleCustomer" >
    <template tabHeading>Customers</template>
    <customers></customers>
  </tab>
  <tab (select)="showProgram()" *ngIf="isRoleProgram">
    <template tabHeading>Programs</template>
    <programs [role]="_isRole"></programs>
  </tab>
  <tab (select)="showMessage()" >
    <template tabHeading>Message Templates</template>
    <message-templates></message-templates>
  </tab>
</tabset>

This is tab order as (message | customers | programs) in this code.But i want to be like (customers| programs| messages) of tab order.So is there any order input property like tabIndex and tabOrder.

yasemincidem avatar Aug 08 '16 07:08 yasemincidem

Implemented an index property for tab component. Waiting for the feat-rc5 branch to be merged before creating a pull request. Change can be viewed/tested from here.

adrianfaciu avatar Aug 30 '16 18:08 adrianfaciu

As a workaround, just add *ngIf="true" to any tab elements that don't have an *ngIf. Issue seems to be lifecycle related.

clabough avatar Mar 10 '17 20:03 clabough

Sorry but... is this closed ?

I have exactly the same issue.

// Thx you for your work Valor

ghost avatar Jun 22 '17 15:06 ghost

+1 same issue. ngIf hides the content tab but not the list item containing the link

ovidiua2003 avatar Jul 04 '17 12:07 ovidiua2003

I there any chance that this will be fixed? When?

romanszedzielorz avatar Dec 15 '17 13:12 romanszedzielorz

+1 I tried the *ngIf="true" word around but it didn't work.

valentinbdv avatar Jan 09 '18 10:01 valentinbdv

I have done working workaround using customClass and adding '_HIDDEN' sufix to my customClass <tab customClass="MY_CLASS_NAME{{!show ? '_HIDDEN' : ''}}"> Class MY_CLASS_NAME_HIDDEN has just: display: none !important;

Important: When you need to show/hide 1st tab, you need to control tab [active] property on your tabs, because when you will hide 1st tab that was active, it will look like no tab is active.

romanszedzielorz avatar Jan 09 '18 10:01 romanszedzielorz

@valentinbdv Would you post what you have that's not working with *ngIf="true"?

clabough avatar Jan 09 '18 15:01 clabough

@clabough as you sugget I added *ngIf="true" in all tabset except the one which already have one ngIf with my condition but it didn't work.

valentinbdv avatar Jan 09 '18 16:01 valentinbdv

+1 same issue, I don't see any 'index' functionality that was previously mentioned either.

rtaft avatar Feb 08 '18 14:02 rtaft

The solution provided by @romanszedzielorz is the only one working - adding *ngIf to all tabs works only until a change to *ngIf condition is detected in the middle element - if it is the case, if condition is true, tab is moved to the end instead staying in the place as declared. Index does not work. Please consider it a serious problem as any dynamic tabs declared other than items in a list are not handled correctly.

t00 avatar Feb 13 '18 16:02 t00

Solved with manual implementation of tabs (ng container with tabs template):

<tabset [vertical]="true">
  <!--Tab manual -->
  <ng-container *ngFor="let ele of myCustomDinamicList()">
    <ul class="nav nav-stacked flex-column nav-tabs">
      <li class="nav-item clickable" 
        (click)="selectedTabIndex = ele" 
        [ngClass]="{ 'nav-item' : true, 'active' : ele === selectedTabIndex }">
        <a [ngClass]="{ 'nav-link' : true, 'active' : ele === selectedTabIndex }">
          <span>{{ele}}</span>
        </a>
      </li>
    </ul>
  </ng-container>
</tabset>

SerCrAsH avatar Feb 20 '18 15:02 SerCrAsH

Any update on that issue? The workaround using ngIf="true" on any other tab works but is really dirty. :(

ghost avatar Apr 04 '18 10:04 ghost

+1. Just ran into this. An index property would work well!

vincentjames501 avatar May 30 '18 14:05 vincentjames501

+1 Any news here? Same problem in my project.

claboran avatar Aug 16 '18 06:08 claboran

I have a tab component inspired by this. I ended up sorting the tabs by id upon ceration. Something in the lines of:


  addTab(tab: TabComponent) {
    const insertPos = this.tabs.findIndex(aTab => aTab.id > tab.id);
    if (insertPos >= 0) {
      this.tabs.splice(insertPos, 0, tab);
    } else {
      this.tabs.push(tab);
    }
  }

Just had to move the addTab invocation from the constructor to ngOnInit to get the id

I wonder if there's anything less intrusive to know the relative positions of the tabs... ElementRef ?

FortinFred avatar Sep 07 '18 21:09 FortinFred

When this problem will be resolved?

Bloodcast69 avatar Dec 04 '18 12:12 Bloodcast69

I've found one solution for today. It doesn't look like a good solution but as is.

  • you have declare the tabset component element in your class
import { TabsetComponent } from 'ngx-bootstrap/tabs';
....
@ViewChild('someTabs') someTabs: TabsetComponent;
  • and then you can sort the tabs manually when you need. For example like here (with lodash)
this.someTabs.tabs  = _(this.someTabs.tabs).sortBy(t => +t.elementRef.nativeElement.id).value();

IlyaMokin avatar Dec 11 '18 19:12 IlyaMokin

Also get this problem, and the *ngIf="true" solution works.

thelastfantasy avatar Jan 17 '19 01:01 thelastfantasy

*ngIf="true" doesn't work for me. I suspect if I build the right amount of delay into a function that returns true. It might work. But this is not a good work around. Edit: I'm currently wrapping tabset inside ngSwitch to maintain the order of tabs.
so if boolean = true, switch to 3 tabs. false switch to 4 tabs. Ideally I would like to just use ngIf on 1 tab. but ordering is important, so now we need to live with this ngSwitch container.

angelayanpan avatar May 09 '19 14:05 angelayanpan

The solution I had use was to put an ngIf on the tabset. I only had 2 different menu arrangements, so I used 2 tabsets, toggle one on depending on which tabs were needed.

rtaft avatar May 09 '19 14:05 rtaft

The solution I had use was to put an ngIf on the tabset. I only had 2 different menu arrangements, so I used 2 tabsets, toggle one on depending on which tabs were needed.

I'm doing similar. but I have 4 tabs. so now html is not pretty. not readable for people who didn't know ngIf is messing up the ordering.

angelayanpan avatar May 09 '19 14:05 angelayanpan

Below is a directive which you can use to specify tab order. Instead of relying on id field which might be used for something else, it "patches" the object with __tabOrder property.

@Directive({
    selector: '[tabOrder]'
})
export class TabOrderDirective implements OnChanges {

    @Input() tabOrder = 0;

    constructor(private tab: TabDirective) { }

    ngOnChanges() {
        (this.tab as any).__tabOrder = +this.tabOrder;
        this.tab.tabset.tabs.sort((a: any, b: any) => a.__tabOrder - b.__tabOrder);
    }
}

usage:

<tab heading="Tab 1" tabOrder="1">
<tab heading="Tab 2" tabOrder="2">

tvoloshyn avatar Jul 25 '19 09:07 tvoloshyn

@tvoloshyn nice man!! Great solution!!

dev01dwu avatar Sep 04 '19 20:09 dev01dwu

Any directives to make tabs mobile friendly? Collapse them into hamburger menu on small screens?

dolphinsd avatar Apr 08 '20 19:04 dolphinsd

@dolphinsd Not really on topic but you can use CSS to make them wrap or make the tabset horizontally scrollable

szh avatar May 01 '20 17:05 szh

has tvoloshyn's solution been considered for production?

smry-web avatar May 07 '20 18:05 smry-web

AFAICT, the issue is that tabs add themselves to the tabset on creation, the tabset just pushes each tab at the end of list. This leads to this behaviour - basically the display order is the creation order.

I think tabset should just obey the order of the tabs within the template; as any other container also does. I would strongly vote against any "order" input - the intuitive and sane behaviour is to take the order the elements are actually declared. This might be achieved by using @ContentChildren or similar - this would also align better with Angular overall, I think.

PapaNappa avatar Nov 18 '20 15:11 PapaNappa

Below is a directive which you can use to specify tab order. Instead of relying on id field which might be used for something else, it "patches" the object with __tabOrder property.

@Directive({
    selector: '[tabOrder]'
})
export class TabOrderDirective implements OnChanges {

    @Input() tabOrder = 0;

    constructor(private tab: TabDirective) { }

    ngOnChanges() {
        (this.tab as any).__tabOrder = +this.tabOrder;
        this.tab.tabset.tabs.sort((a: any, b: any) => a.__tabOrder - b.__tabOrder);
    }
}

usage:

<tab heading="Tab 1" tabOrder="1">
<tab heading="Tab 2" tabOrder="2">

wasn't working for me when I looked at it some days ago. the issue was not this directive but rather my code as i was using tab stuff.... for some tabs and it wasn't working due to

danishaali9 avatar May 25 '23 14:05 danishaali9

Below is a directive which you can use to specify tab order. Instead of relying on id field which might be used for something else, it "patches" the object with __tabOrder property.

@Directive({
    selector: '[tabOrder]'
})
export class TabOrderDirective implements OnChanges {

    @Input() tabOrder = 0;

    constructor(private tab: TabDirective) { }

    ngOnChanges() {
        (this.tab as any).__tabOrder = +this.tabOrder;
        this.tab.tabset.tabs.sort((a: any, b: any) => a.__tabOrder - b.__tabOrder);
    }
}

usage:

<tab heading="Tab 1" tabOrder="1">
<tab heading="Tab 2" tabOrder="2">

works! thanks!

irfnrzk avatar Dec 19 '23 00:12 irfnrzk