Look like fix to https://github.com/valor-software/ng2-bootstrap/issues/696 (thanks BTW) may have broken something.
Changing a components tabs no longer causes the old tabs to go away.
HTML
<tabset>
<tab *ngFor="let tabz of tabs"
....
Component
private tabs: any[];
...
in ngOnInit
this.tabs = [...]
at some point in the future
this.tabs = [...]
Original tabs from onInit should go away and be replaced with new tabs. Instead original tabs are still on screen along with new ones.
(Actual use case is my workaround described in https://github.com/valor-software/ng2-bootstrap/issues/699 where I veto tab selection by replacing the current tab state with the previous tab state. This seems to be a bug in any case but perhaps its time for me to revisit that, maybe something has changed since then)
The same problem here. Works with 1.1.16, but not with 1.1.16-11.
Ironically my workaround to allow me to grab new versions of ng2-bootstrap is now to add:
(TabDirective as any).prototype.ngOnDestroy = function () {
this.tabset.removeTab(this);
};
similar issue with 1.1.16-11, when I remove any entry essentially from tabs the tab stays there.
@slubowsky I had to remove this because of another issue, with multiply events triggering on page destroy >.<
@valorkin I know. I authored that issue :) but I have a workaround in place for that one already (see that issue where someone discusses something similar to what I did) so basically just reverting back to that state for now.
Why not just have TabDirective.OnDestroy pass a flag that says not to event the removal or something simple like that?
@slubowsky 's suggestion, in my opinion, is the best way to solve it.
Here are my analysis and current workaround:
I think the root of the problem is there are two sets of 'tabs' being maintained, one is the 'tabs' provided/maintained by our client code(let's call it ClientTab), another is the set of TabDirective maintained by the library.
Analysis:
In order for the library to function properly, we have to guarantee that these two sets of 'tabs' are synced probably, which means:
ClientTab is created, a corresponding TabDirective shall also be created.ClientTab is destroyed, its corresponding TabDirective shall also be destroyed.TabDirective is closed by a user action (clicking on the remove button), its corresponding ClientTab shall also be destroyed.In the previous version, 1 and 2 are well maintained. The problem is with 3, as the removed (and the cascading select ) event fires when
remove button TabDirective is destroyed when the whole containing view is being destroyed (for example, switching to another route).and our client code is unable (at least not as I can perceive) to distinguish these two scenarios, thereafter, we cannot maintain our ClientTab states properly. For example, if:
This was broken because in the previous version, when switching to another route, removed and select events got fired inevitably and our ClientTab states got messed up.
By removing the ngOnDestroy in TabDirective, we are able to fix this problem. But, by doing so, we break the rule 2:
- When a
ClientTabis destroyed, its correspondingTabDirectiveshall also be destroyed.
because when a TabDirective got destroyed with the ClientTab, it failed to remove itself from its TabsetComponent 's state and therefore got recreated later.
Current workaround:
When a ClientTab got removed, we remove its corresponding TabDirective from the TabsetComponent manually. Assuming:
TabDirective and ClientTab have the one-to-one relationship and their positions are the same in the lists they reside.TabsetComponent by using the ViewChild API.then
let idx = ...
clientTabsList.split(idx, 1);
tabset.removeTab(tabset.tabs[idx])
Notice this remove operation will fire the removed event and the possibly cascading select event as well, we need to handle them probably.
Thanks for the guidance, guys!
In Typescript I am doing this to get hold of Tabset component:
export class PriorityDataComponent implements OnInit {
@ViewChild(TabsetComponent)
private ts: TabsetComponent;
and this to replace old tabs with new ones:
..................
// Clear old tabs
while (this.ts.tabs[0] != null){
this.ts.removeTab(this.ts.tabs[0])
}
// Insert new tabs
this.tabs = [];
newValue.forEach(p => {
let tab = new PriorityTab(p);
this.tabs.push(tab)});
this.setActiveTab(0);
..................
Sorry I that I did not know how to format the code properly!
I'm having this issue on 1.3.1 as well. Any signs of it being officially fixed?
Not yet
What's the current state on this? I am also facing this issue right now!
Is there a workaround that I can put in place?
_edit_: I fixed this by accident. Since my data loads async I remove the tabset (using *ngIf) during loading, to show a progress bar. after loading finishs the tabset gets build newly and all the old tabs are gone!
<tabset *ngIf="!loading">
</tabset>
So just use a boolean on ngIf that you toggle when you are changing your data!
While trying to hack TabDirective, I found another Bootstrap feature that could achieve similar results: Button>Radio. This alternate approach addresses the issue of old tabs not being removed after routing to a new component like so:
Import ButtonsModule as usual,
//Assuming you use Angular-cli
import { ButtonsModule } from 'ng2-bootstrap';
@NgModule({
imports: [ButtonsModule.forRoot(),...]
})
Then simply use it like so:
<div class="btn-group">
<label
*ngFor="let item of collection"
(click)="routeSomewhere(item.title)"
class="btn btn-primary"
[(ngModel)]="radioModel"
btnRadio="{{item.title}}">
{{item.title}}
</label>
</div>
We add a (click) event to fire off a method routeSomewhere that in turn does the routing. The radio buttons act like tabs because only one can be active. It has the extra benefit of showing the active state / selected button. Hope that helps.
Any news about this bug? I still have it in version 1.6.6
The fact this still exists, is stupid... I think i'll use some other framework.
fix published in v1.7+
Most helpful comment
What's the current state on this? I am also facing this issue right now!
Is there a workaround that I can put in place?
_edit_: I fixed this by accident. Since my data loads async I remove the tabset (using *ngIf) during loading, to show a progress bar. after loading finishs the tabset gets build newly and all the old tabs are gone!
So just use a boolean on ngIf that you toggle when you are changing your data!