Reputation: 487
I'm using angular mat-tab-group How do i force angular to bind html element of inactive tabs, below is the html implementation
<mat-tab label="Test">
<app-test></app-test>
</mat-tab>
the test.component.ts file did initialize and run, but the html element is not binded, view attached image below. is there a way to force angular to bind it? i'm intergrating some 3rd party libary that requires the html element to be binded when the component.ts files start executing or else it will break.
Upvotes: 5
Views: 2813
Reputation: 58019
I'm afraid that you can not, you can use the events (selectedTabChange) or (selectedIndexChange). NOTE: If you see the API about TabMatGroup in @Output you has all the "events" you can "reach", you allways use, e.g. (selectedTabChange)="yourFunction($event)"
and the argument of the function is the indicate in the API under "EmitterEvent" -in this case is of type MatTabChangeEvent
-
Exist another option that is create a tabgroup without content, and use a variable index
//in your .ts
index=0
Then you create an .html like
<!-- see that you use margin-bottom and animationDuration -->
<mat-tab-group style="margin-bottom:5px;" animationDuration="0"
mat-align-tabs="start" (selectedIndexChange)="index=$event">
<!-- you makes the mat-tabs "empty" -->
<mat-tab label="First"></mat-tab>
<mat-tab label="Second"></mat-tab>
<mat-tab label="Third"></mat-tab>
</mat-tab-group>
<!--here you put your content using [style.display]="none" when
the index is not equal to hte value (remember index begings by 0-->
<div [style.display]="index!=0?'none':null">
Content 1
</div>
<div [style.display]="index!=1?'none':null">
Content 2
</div>
<div [style.display]="index!=2?'none':null">
Content 3
</div>
But you need create the "animation" manually. For this you can add the animation to your component
animations: [
trigger('flyInOut', [
transition(':decrement', [
style({ transform: 'translateX(100%)' }),
animate(200)
]),
transition(':increment', [
style({ transform: 'translateX(100%)' }),
animate(200)
])
])
]
And use an auxiliar variable "indexOld". Then use the animation in the html
<mat-tab-group style="margin-bottom:5px;" animationDuration="0"
mat-align-tabs="start" (selectedIndexChange)="index=$event">
<mat-tab label="First"></mat-tab>
<mat-tab label="Second"></mat-tab>
<mat-tab label="Third"></mat-tab>
</mat-tab-group>
<!--see that now I use "indexOld", not "index"
when the animation is done, you equal indexOld to index-->
<div [style.display]="indexOld!=0?'none':null" [@flyInOut]="index" (@flyInOut.done)="indexOld=index">
Content 1
</div>
<div [style.display]="indexOld!=1?'none':null" [@flyInOut]="index" (@flyInOut.done)="indexOld=index">
Content 2
</div>
<div [style.display]="indexOld!=2?'none':null" [@flyInOut]="index" (@flyInOut.done)="indexOld=index">
Content 3
</div>
See the stackblitz
NOTE: Really it's not "exact" to the animation in mat-tab, fell free to change the animations to make it more closer
Update a animation that "simulate" the animation of a mat-tab
we need see two "tabs" at time, so we need "wrapper" the tabs in a div with position relative and makes position absolute. This makes we need know the "height" of the tabs. So we are going to use "visibility" instead of "display", but first we are going to defined four animations
animations: [
trigger('flyInOut', [
transition('*=>inmore', [
style({ transform: 'translateX(100%)' }), //start in
animate(200)
]),
transition('*=>inless', [
style({ transform: 'translateX(-100%)' }), //start in
animate(200)
]),
transition('*=>outless', [
animate(200, style({ transform: 'translateX(100%)' })) //end in
]),
transition('*=>outmore', [
animate(200, style({ transform: 'translateX(-100%)' })) //end in
])
])
]
We are going to see the tab if is "i" is index or indexOld and to get the "animation" we are going to use a function
getAnimation(i:number,indexOld:number,index:number)
{
const from=(i==index)?'in':(i==indexOld)?'out':null
if (from && indexOld!=index)
return from+(indexOld>index?'less':'more')
return null
}
And the .html like
<div class="wrapper" [style.height]="maxHeigth">
<div #tab [style.visibility]="index!=0 && indexOld!=0?'hidden':null" [@flyInOut]="getAnimation(0,indexOld,index)"
(@flyInOut.done)="indexOld=index">
Content 1
</div>
<div #tab [style.visibility]="index!=1 && indexOld!=1?'hidden':null" [@flyInOut]="getAnimation(1,indexOld,index)"
(@flyInOut.done)="indexOld=index">
Content 2
</div>
<div #tab [style.visibility]="index!=2 && indexOld!=2?'hidden':null" [@flyInOut]="getAnimation(2,indexOld,index)"
(@flyInOut.done)="indexOld=index">
Content 3
</div>
</div>
See that the wrapper class indicate
.wrapper
{
position:relative;
width:100%;
}
.wrapper>div
{
position:absolute;
width:100%;
}
The last step is know the "maxHeigth", so, we are going to get the "tabs" using viewChildren and, in ngAfterViewInit enclosed in setTimeout, get the maxHeigth
maxHeigth:string;
@ViewChildren('tab') tabs:QueryList<ElementRef>
ngAfterViewInit()
{
setTimeout(()=>{
this.maxHeigth=this.tabs.map(x=>x.nativeElement.getBoundingClientRect().height)
.reduce((a,b)=>a>b?a:b,0)+'px'
})
}
You can see the final stackblitz
Upvotes: 4