Utilisation de Angular 2.3.1 et ng-bootstrap 1.0.0-alpha.18. J'essaie de sélectionner par programme un onglet basé sur l'ID dans le composant plutôt que dans le modèle. Le but est pour extraire le paramètre de l'url et l'utiliser pour sélectionner l'onglet dans ngOnInit
le gabarit
<section id="policy-terms">
<ngb-tabset>
<ngb-tab title="Terms and Privacy" id="terms">
<template ngbTabContent>
<div class="container page-content">
</div>
</template>
</ngb-tab>
<ngb-tab title="Company Policy" id="policy">
<template ngbTabContent>
<div class="container page-content">
</div>
</template>
</ngb-tab>
</ngb-tabset>
</section>
Et le code composant:
import { Component, OnInit } from '@angular/core';
import { NgbTabset } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-policy-terms',
templateUrl: './policy-terms.component.html',
styleUrls: ['./policy-terms.component.scss'],
providers: [
NgbTabset
]
})
export class PolicyTermsComponent implements OnInit {
constructor(
public tabset: NgbTabset
) { }
ngOnInit() {
this.tabset.select('policy');
}
}
Cela produit juste une erreur:
Erreurs du journal de la console
Comment puis-je accéder à cette méthode?
Dans AngularJs 1.x, utiliser ui-router pour configurer des routes de noms était simple. Dans Angular 2 avec Ng-Bootstrap, ce n'est pas aussi évident. Du côté positif, ce dont vous avez besoin est disponible dans les bibliothèques natives Angular 2).
export const appRoutes: Routes =
[
{ path: 'prospect/:prospectid/details', component: ProspectTabsView, data:{name:'details'} },
{ path: 'prospect/:prospectid/appointments', component: ProspectTabsView, data:{name:'appointments'} },
{ path: 'prospect/:prospectid/followups', component: ProspectTabsView, data:{name:'followups'} },
{ path: 'prospect/:prospectid/contacts', component: ProspectTabsView, data:{name:'contacts'} },
{ path: '', component: DashboardView },
{ path: '**', redirectTo: '', pathMatch: 'full'}
];
La configuration est simple à une exception près: l'attribut [data]. Vous remarquerez qu'il a une clé appelée name
. C'est le nom de l'itinéraire. Considérez-le comme un attribut de données comme un sac de données. Vous pouvez ajouter plus que le nom de l'itinéraire.
<ngb-tabset #tabs>
<ngb-tab id="details">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect', prospectId, 'details']">Details</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
<ngb-tab id="contacts">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect',prospectId,'contacts']">Contacts</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
<ngb-tab id="appointments">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect', prospectId, 'appointments']">Appointments</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
<ngb-tab id="followups">
<ng-template ngbTabTitle>
<a [routerLink]="['/prospect', prospectId, 'followups']">Follow Ups</a>
</ng-template>
<ng-template ngbTabContent>
</ng-template>
</ngb-tab>
</ngb-tabset>
Il n'y a rien de magique dans le balisage de l'onglet ci-dessus, il y a quelques choses que vous souhaitez noter: d'abord dans le ngb-tabset
élément, nous avons déclaré la variable #tab
. Nous utiliserons #tab
plus loin dans le composant. Deuxièmement, chaque nbg-tab
a un ensemble id
qui correspond au nom que nous avons défini dans la configuration de l'itinéraire (c'est-à-dire data:{name:'followups'}
).
import {
AfterViewChecked, Component, OnInit,
ViewChild
} from '@angular/core';
import '../../assets/css/styles.css';
import {ActivatedRoute} from "@angular/router";
import {NgbTabset} from "@ng-bootstrap/ng-bootstrap";
@Component({
templateUrl: './tabs.view.html'
})
export class ProspectTabsView implements OnInit, AfterViewChecked{
prospectId: number;
selectedTab:string;
@ViewChild('tabs')
private tabs:NgbTabset;
constructor(private route: ActivatedRoute) {
this.route.data.subscribe(d=>{
this.selectedTab = d.name;
});
}
ngOnInit(): void {
this.route.params.subscribe(
params => {
this.prospectId = +params['prospectid'];
}
);
}
ngAfterViewChecked(): void {
if(this.tabs) {
this.tabs.select(this.selectedTab);
}
}
}
La partie la plus difficile de cet exercice a été d'obtenir l'ordre d'exécution correct. Si ce n'est pas correct, une collection ou une propriété ne sera pas initialisée avant que vous ne l'utilisiez. Nous commencerons par le haut de la classe et descendrons.
Tout d'abord, nous avons les variables. prospectId
est la clé primaire des données, selectedTab
est le nom de l'onglet actuellement sélectionné, et enfin, nous avons la variable tabs
. tabs
est une référence à l'attribut (#tab
) nous avons ajouté au ngb-tabset
élément.
Vient ensuite le constructor
. Ce n'est pas évident dans la documentation, mais data
est un Observable<data>
. Pour capturer la valeur, nous souscrivons à la propriété data
de la route.
Le constuctor
suit le ngOnInit
. Ce n'est pas important pour les onglets, mais cela capture le prospectId que nous utilisons dans le routage de l'onglet. Si vous ne disposez d'aucune donnée dynamique sur vos itinéraires, vous n'en avez pas besoin.
Enfin, nous avons ngAfterViewChecked
. Pour router le tabs
, c'est le plus important. Ici, nous utilisons la variable tabs
que nous avons capturée à partir du balisage et c'est là que nous transmettons le nom de l'onglet sélectionné à tabs
pour changer l'onglet sélectionné.
Pour que cela fonctionne correctement, j'ai dû ajouter pour accrocher dans l'événement tabChange
sur le ngb-tabset
.
<ngb-tabset [activeId]="selectedTab" #tabs (tabChange)="onTabChange($event)">
De plus, j'ai dû coder en dur les routes dans la fonction onTabChange.
onTabChange($event: NgbTabChangeEvent) {
let routes = {
details: `/prospect/${this.prospectId}/details`,
appointments: `/prospect/${this.prospectId}/appointments`,
followups: `/prospect/${this.prospectId}/followups`,
notes: `/prospect/${this.prospectId}/notes`,
dials: `/prospect/${this.prospectId}/dials`,
};
this.router.navigateByUrl(routes[$event.nextId]);
}
Cela se produit car vous appelez select on tabs avant même que les onglets aient été initialisés. NgTabset sont initialisés une fois la vue initiée. J'ai utilisé un booléen pour voir s'ils ont été initialisés avant d'appeler select.
tabsInitialized: boolean = false;
@ViewChild('tabs') public tabs:NgbTabset;
ngAfterViewInit() {
this.tabsInitialized = true;
}
ngOnChanges(){
if(this.tabsInitialized){
this.tabs.select('dashboard');
}
}
...
Si quelqu'un veut le faire à partir du modèle, la meilleure approche est:
<ngb-tabset #tabRef="ngbTabset">
<ngb-tab title="Tab-1" id="tab1">
<ng-template ngbTabContent>
<p> Tab 1 Content</p>
</ng-template>
</ngb-tab>
<ngb-tab title="Tab-2" id="tab2">
<ng-template ngbTabContent>
<p> Tab 2 Content</p>
</ng-template>
</ngb-tab>
</ngb-tabset>
<div>
<button class="btn" (click)="tabRef.select('tab2')">Select tab with id tab2</button>
</div>
Mettre une référence sur l'élément
<ngb-tabset #tabs>
Utilisez un ViewChild pour contrôler l'onglet
export class PolicyTermsComponent implements OnInit {
private tabs:NgbTabset;
@ViewChild('tabs') public set _tabs(tabs: NgbTabset)
{
if(!tabs) return;
this.tabs = _tabs;
this.tabs.select('policy');
}
}
J'ai déplacé l'exécution de la sélection vers un ensemble afin d'être sûr que la page a correctement créé le composant tabs et qu'il peut être référencé et utilisé.
Le problème que vous rencontrez est que vous exécutez le code dans la mauvaise partie de la boucle d'événements. Vous pouvez utiliser le await/async
pour pousser le réglage de l'onglet actif à plus tard dans la boucle d'événement avec d'autres micro-tâches
// ... other stuff
{ path: ":id/:tabName", component: ViewTabsComponent },
// ... other stuff
<ngb-tabset #myTabs>
<ngb-tab title="Terms and Privacy" id="terms">
<template ngbTabContent>
<p>content</p>
</template>
</ngb-tab>
<ngb-tab title="Company Policy" id="policy">
<template ngbTabContent>
<p>other content<\p>
</template>
</ngb-tab>
</ngb-tabset>
@ViewChild("myTabs", { static: true, read: NgbTabset }) myTabs: NgbTabset;
async ngOnInit() {
const params = await this.route.paramMap
.pipe(
map((params: ParamMap) => ({ tabName: params.get("tabName") })),
take(1) // <-- force to complete
).toPromise();
this.myTabs.select(`${params.tabName}`);
}
cela fonctionne avec