web-dev-qa-db-fra.com

Le routeur Angular2 garde la chaîne de requête

J'ai écrit une application Angular2 (v2.0.1) qui utilise le routeur. Le site Web est chargé avec plusieurs paramètres de chaîne de requête. L'URL complète ressemble donc initialement à ceci:

https://my.application.com/?param1=val1&param2=val2&param3=val3

Dans ma configuration d'itinéraire, j'ai une entrée qui redirige un itinéraire vide:

const appRoutes: Routes = [
    {
        path: '',
        redirectTo: '/comp1',
        pathMatch: 'full'
    },
    {
        path: 'comp1',
        component: FirstComponent
    },
    {
        path: 'comp2',
        component: SecondComponent
    }
];

Mon problème est que, après le démarrage de l'application, l'URL ne contient plus les paramètres de la requête. Elle se présente plutôt comme suit:

https://my.application.com/comp1

Est-il possible de configurer le routeur afin qu'il conserve la chaîne de requête initiale lors de la navigation?

Je vous remercie
Lukas

36
Lukas Kolletzki

Je ne pense pas qu'il y ait un moyen de définir cela dans la configuration des routes. 

Actuellement, il est pris en charge pour routerLinks et navigation impérative pour permettre 

Vous pouvez ajouter une garde à l’itinéraire de chemin vide, où la navigation vers la route /comp1 est effectuée.

router.navigate(['/comp1'], { preserveQueryParams: true }); //deprecated see update note
router.navigate(['/comp1'], { queryParamsHandling: "merge" });

Il existe un PR pour permettre de configurer preserveQueryParams globalement.

Note de mise à jour: from https://angular.io/api/router/NavigationExtras , preserveQueryParams est obsolète, utilisez plutôt queryParamsHandling.

37

Si vous naviguez à l'aide d'un modèle HTML, vous pouvez utiliser 

<a [routerLink]="['/page-2']" [routerLinkActive]="['is-active']" queryParamsHandling="merge">

Il convient de noter que le paramètre queryParamsHandling est sans crochets.

31
Kamalpreet

La réponse de Günter Zöchbauer devrait fonctionner correctement mais, pour une raison quelconque, cela ne fonctionne pas du tout pour moi. Ce qui a fini par fonctionner, c’est de passer directement la queryParams au lieu de la «préserver».

Voici à quoi ressemble ma garde:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    (...)
    this.router.navigate(['login'], { queryParams: route.queryParams });
}
6
AArias

Vous pouvez rechercher https://github.com/angular/angular/issues pour une demande de fonctionnalité similaire à celle-ci. S'il n'en existe pas, soumettez une demande de fonctionnalité. 

En attendant: je pense que vous devrez créer un composant sur le chemin: '', dans le seul but de rediriger ensuite vers '/ comp1' tout en préservant les paramètres QueryString. 

2
Martin

Il s’avère que la manière non documentée de procéder sans autre piratage consiste à simplement supprimer la barre oblique située dans le champ "redirectTo". Puisque vous faites correspondre le chemin complet, vous pouvez être sûr qu'il fera ce que vous voulez (c.-à-d. Aucun segment d'URL surprise) et comme ce n'est plus une cible absolue, Angular préservera les paramètres de requête actuels.

Donc dans ce cas

{
  path: '',
  redirectTo: '/comp1',
  pathMatch: 'full'
}

devient:

{
  path: '',
  redirectTo: 'comp1',
  pathMatch: 'full'
}

Source: https://github.com/angular/angular/issues/13315

1
Christopher

capturer l'URL d'origine dans -base href-

https://example.com/order?id=123

alors il va présister

https://example.com/order?id=123#/product

0
dot52

Si vous naviguez à l'aide d'un modèle HTML, vous pouvez également utiliser preserveQueryParams="true"

Notez que preserveQueryParams est sans crochet.

Par exemple: 

<a [routerLink]="['/navigate-to']" preserveQueryParams="true">

0
Vandesh

Il existe une solution de contournement utilisant des itinéraires secondaires, car Angular les conservera tout au long de la navigation sur les itinéraires principaux.

Tout d’abord, ajoutez une sortie de routeur nommée dans votre composant principal:

<router-outlet name="params"><router-outlet>

Créez ensuite un composant factice vers lequel acheminer:

@Component({
    template: ""
})
export class ParamsComponent {}

et définir une route pour instancier ce composant dans la sortie nommée:

{
    path: ':val1',
    component: ParamsComponent,
    outlet: "params"
}

Changez la navigation de votre application en:

https://my.application.com/(params:val1)

Si vous regardez un ActivatedRoute, vous pouvez trouver la route "params" en utilisant:

  var paramsRoute = this.activatedRoute.route.children.find(r => r.outlet == "params");

Si paramsRoute est null, l'URL ne contient pas le (params: val1).

Cette partie suivante devient un peu "hacky" car la route secondaire est instanciée après la route principale lors du chargement initial. Pour cette raison, jusqu'à ce que votre application soit complètement chargée, paramsRoute.snapshot peut être null. Il existe une propriété privée "_futureSnapshot" qui contiendra les paramètres de la route au démarrage initial ... et qui persistera tout au long de la vie de l'application. Vous pouvez y accéder en utilisant:

var queryParams = 
      paramsRoute
      ? paramsRoute["_futureSnapshot"].params
      : {};
var val1 = queryParams["val1"];

Étant donné que _futureSnapshot ne fait pas partie de l'API publique, il s'agit probablement d'un champ que nous ne sommes pas censés utiliser. Si vous vous sentez mal à l'aise de l'utiliser, vous pourriez probablement vous abonner à paramsRoute.params, mais cela compliquera probablement vos composants.

if (paramsRoute) {
    paramsRoute.params.subscribe(params => {
        this.queryParams = params;
        this.loadData();
    });
} else {
    this.queryParams = {};
    this.loadData();
}

========= AMENDEMENT ==============

J'ai trouvé un moyen encore plus efficace d'extraire les paramètres de requête, ce qui n'est certainement PAS fastidieux ... Dans un composant ou un service instancié avant le routage, ajoutez la logique suivante:

    const routeRecognizedSubscription = this.router.events
        .filter(e => e instanceof RoutesRecognized)
        .subscribe((e: RoutesRecognized) => {
            const paramsRoute = e.state.root.children.find(r => r.outlet == "params");
            if (paramsRoute) {
                // capture or use paramsRoute.params 
            }
            routeRecognizedSubscription.unsubscribe();
        });

Ce code s'abonne temporairement aux événements RoutesRecognized qui se produisent avant la navigation. Après avoir reçu le premier événement, il se désabonnera automatiquement, car nous ne devons le faire qu'au démarrage de l'application.

Lors du premier événement, nous recherchons l'état correspondant à la sortie "params". Si trouvé, la propriété params contiendra les données dont nous avons besoin. Pas besoin d'accéder aux propriétés privées.

0
Greg Petrites