web-dev-qa-db-fra.com

Route de recharge angulaire 2 sur changement de paramètre

J'écris actuellement ma première application Angular 2 . J'ai un composant OverviewComponent qui comporte le modèle simple suivant:

<div class="row">
  <div class="col-lg-8">
    <router-outlet></router-outlet>
  </div>
  <div class="col-lg-4">
    <app-list></app-list>
  </div>
</div>

lors de l'accès à l'URL /, mon routeur me redirige vers /overview qui charge ensuite une carte dans le routeur-prise. Le <app-list> contient une liste d'éléments pouvant être cliqués, ce qui déclenche l'affichage d'un <app-detail> à la place du composant d'application. Par conséquent, je passe l'id du fichier json référent dans l'URL comme suit: /details/:id (dans mes itinéraires).

Tout ce qui précède fonctionne parfaitement. Si je clique maintenant sur l'un des éléments de la liste, les détails sont affichés, MAIS lorsque je sélectionne un autre élément de la liste, la vue ne change pas pour les nouveaux détails. L'URL change mais le contenu n'est pas rechargé. Comment puis-je effectuer une réinitialisation du composant DetailComponent?

28
hGen

Comme dans la première version finale, ceci est résolu. 

Il suffit de faire très attention à réinitialiser correctement l'état du composant lorsque le paramètre change

this.route.params.subscribe(params => {
    this.param = params['yourParam'];
    this.initialiseState(); // reset and set based on new parameter this time
});
29
gpanagopoulos

Vous pouvez modifier la routeReuseStrategy directement au niveau du composant:

constructor(private router: Router) {

      // force route reload whenever params change;
      this.router.routeReuseStrategy.shouldReuseRoute = () => false;

}

De même, la stratégie de réutilisation peut être modifiée globalement. 

Cela ne résout pas nécessairement votre problème directement, mais voir comment cette question est le premier résultat de recherche pour " angular 2 reload url si les paramètres de la requête changent ", cela pourrait éviter à la personne suivante de fouiller dans les problèmes de github.

54
Nik

Une autre alternative qui devrait être ajoutée ici consiste à fournir un RouteReuseStrategy à votre module.

providers: [
  {
    provide: RouteReuseStrategy,
    useClass: AARouteReuseStrategy
  }
]

Le comportement par défaut du routeur est de réutiliser la route si la configuration est la même (ce qui est le cas lorsque vous modifiez uniquement le paramètre: id dans cette question). En modifiant la stratégie pour ne pas réutiliser l'itinéraire, le composant est rechargé et vous n'avez pas besoin de vous abonner aux modifications de l'itinéraire dans le composant.

Une implémentation de RouteReuseStrategy pourrait ressembler à ceci:

export class AARouteReuseStrategy extends RouteReuseStrategy {
  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    return false;
  }
  store(route: ActivatedRouteSnapshot, handle: {}): void {

  }
  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return false;
  }
  retrieve(route: ActivatedRouteSnapshot): {} {
     return null;
 }
 shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
   return false; // default is true if configuration of current and future route are the same
 }
}

J'ai aussi écrit quelques mots à ce sujet ici:

https://pjsjava.blogspot.no/2018/01/angular-components-not-reloading-on.html

8
Peter Salomonsen

Je ne sais pas s'il existe une solution au problème similaire à celle que je vais proposer ici, alors je le ferai quand même:

J'ai réussi à réaliser un "faux" rechargement de la manière suivante.

En gros, j'ai créé un composant qui me redirige vers le "vrai" composant que je souhaite utiliser:

@Component({
  selector: 'camps-fake',
  template: ''
})
export class FakeComponent implements OnInit {

  constructor(private _router:Router,
              private _route:ActivatedRoute)
  { }

  ngOnInit() {
    let id:number = -1;
    this._route.params.forEach((params:Params) => {
      id = +params['id'];
    });

    let link:any[] = ['/details', id];
    this._router.navigate(link);
  }

}

Ainsi, en sélectionnant un élément de la liste, le routeur accédera à /fake/:id, qui extrait simplement l'ID de l'URL et accède au composant "réel".

Je sais qu’il existe peut-être un moyen plus simple ou plus sophistiqué, mais je pense que cette solution fonctionne plutôt bien, car le faux ne attire pas vraiment l’attention. Le «clignotement» lorsque la page est rechargée est un aspect négatif, mais dans la mesure de mes connaissances en CSS, il pourrait y avoir une transition pour le couvrir.

7
hGen

Il est possible de détecter tout changement dans les paramètres reçus. Dans mon cas, je charge les informations à l'aide d'une résolution, de sorte que je n'ai pas besoin du paramètre (détecte uniquement si cela change). Ceci est ma solution finale:

public product: Product;
private parametersObservable: any;

constructor(private route: ActivatedRoute) {
}

ngOnInit() {
  this.parametersObservable = this.route.params.subscribe(params => {
    //"product" is obtained from 'ProductResolver'
    this.product = this.route.snapshot.data['product'];
  });
}

//Don't forget to unsubscribe from the Observable
ngOnDestroy() {
  if(this.parametersObservable != null) {
    this.parametersObservable.unsubscribe();
  }
}
3
Alexis Gamarra
this.route.paramMap.subscribe(params => {
  //fetch your new parameters here, on which you are switching the routes and call ngOnInit()
  this.ngOnInit();
 });

Il vous suffit d’appeler ngOnInit () depuis l’intérieur de paramMap et il initialisera la page entière avec les données récemment chargées.

2
cyperpunk

Je l'ai résolu en utilisant event, si le composant enfant envoie un nouveau lien et un événement, le parent peut alors trouver le changement et appeler une fonction de rechargement qui rechargera les données nécessaires . Une autre option consiste à s'abonner. aux paramètres route, et trouvé quand il change Mais je pense que les gars de angular2 devraient penser à ajouter des paramètres à la fonction router.navigate, ce qui peut forcer le rechargement. (forceReload = true)

2
user3728728

Ce n'est actuellement pas directement pris en charge. Voir aussi https://github.com/angular/angular/issues/9811

Qu'est-ce que vous pouvez faire est quelque chose comme

<div *ngIf="doShow" class="row">
  <div class="col-lg-8">
    <router-outlet></router-outlet>
  </div>
  <div class="col-lg-4">
    <app-list></app-list>
  </div>
</div>
doShow:boolean: true;

constructor(private _activatedRoute: ActivatedRoute, private _router:Router, private cdRef:ChangeDetectorRef) {
  _router.routerState.queryParams.subscribe(
    data => {
      console.log('queryParams', data['st']); 
      this.doShow = false;
      this.cdRef.detectChanges();
      this.doShow = true;
  });
}

(pas testé)

1
Günter Zöchbauer

espérons que cela aidera.

constructor(private router: Router){
 // override the route reuse strategy

 this.router.routeReuseStrategy.shouldReuseRoute = function(){
    return false;
 }

 this.router.events.subscribe((evt) => {
    if (evt instanceof NavigationEnd) {
       // trick the Router into believing it's last link wasn't previously loaded
       this.router.navigated = false;
       // if you need to scroll back to top, here is the right place
       window.scrollTo(0, 0);
    }
});

}
0
Ashutosh Kushawaha