ngx-bootstrap
ngx-bootstrap copied to clipboard
fix(tabs): order not working with ngIf\dynamic directives
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.
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.
As a workaround, just add *ngIf="true" to any tab elements that don't have an *ngIf. Issue seems to be lifecycle related.
Sorry but... is this closed ?
I have exactly the same issue.
// Thx you for your work Valor
+1 same issue. ngIf hides the content tab but not the list item containing the link
I there any chance that this will be fixed? When?
+1 I tried the *ngIf="true" word around but it didn't work.
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.
@valentinbdv Would you post what you have that's not working with *ngIf="true"?
@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.
+1 same issue, I don't see any 'index' functionality that was previously mentioned either.
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.
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>
Any update on that issue? The workaround using ngIf="true" on any other tab works but is really dirty. :(
+1. Just ran into this. An index property would work well!
+1 Any news here? Same problem in my project.
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 ?
When this problem will be resolved?
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();
Also get this problem, and the *ngIf="true"
solution works.
*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.
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.
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.
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 nice man!! Great solution!!
Any directives to make tabs mobile friendly? Collapse them into hamburger menu on small screens?
@dolphinsd Not really on topic but you can use CSS to make them wrap or make the tabset horizontally scrollable
has tvoloshyn's solution been considered for production?
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.
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
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!