3
votes

Comment définir les paramètres de requête par défaut pour Route dans Angular 7?

Dans notre application Angular-7, nous utilisons @ngrx et @ ngrx / router-store pour mettre les paramètres de requête dans l'état.

Quelques composants de l'application sont des listes paginées. Nous avons chaque liste en tant que composant et le composant de pagination inclus dans chaque liste.

La page actuelle est stockée dans l'URL en tant que paramètre de requête: user /: userId / agent? Page = 0 et le PaginationComponent récupère la page courante à partir de state.router.state.queryParams.page . Cependant, si un utilisateur accède à l'URL user /: userId / agent , queryParams.page renvoie undefined.

Nous pourrions résoudre ce problème en utilisant state.router.state.queryParams.page || 0 dans chaque composant mais je me demande s'il existe un moyen plus simple - une Route sans paramètres de requête peut-elle être redirigée vers une Route avec des paramètres de requête ?

J'ai essayé en utilisant la redirection la plus évidente:

{ path: 'user/:userId/agent', redirectTo: '/user/:userId/agent?page=0', pathMatch: 'full' },
{ path: 'user/:userId/agent?page=0', component: AgentListComponent },

mais j'obtiens Erreur: ne peut correspondre à aucune route. Segment d'URL: 'user / max / agent' .

La seule demande de fonctionnalité que j'ai trouvée était celui-ci où l'erreur ci-dessus apparaît.


3 commentaires

Je pense que c'est une question large, car il existe de nombreuses façons. Vous pouvez utiliser un garde qui redirige, le composant pourrait le faire, etc. etc. Mais Angular ne peut pas faire correspondre les routes avec les paramètres de requête. Ce n'est pas une fonctionnalité prise en charge, et je ne pense pas que ce le sera jamais.


Pour être honnête, ajoutez || 0 est vraiment le moins d'effort et le plus facile à maintenir. Je pense que vous réfléchissez trop au problème, et les URL plus courtes sont plus faciles à lire.


Ajout de || 0 à chaque composant dans lequel il est utilisé est le moins d'effort, mais cela contredit le principe DRY.


3 Réponses :


3
votes

Pour votre question en particulier:

Une Route sans paramètres de requête peut-elle être redirigée vers une Route avec des paramètres de requête?

Je ne pense pas que cela puisse fonctionner parce que le? dans une requête est un séparateur, qui ne fait pas partie de la chaîne de requête d'une URL.

Alternative 1 - puisque vous utilisez ngrx, une façon de le faire est d'utiliser le custom sérialiseur. Les documents du site ngrx.io montrent un exemple de retour des paramètres avec sérialisation. C'est ici que vous pouvez ajouter une logique pour ajouter une valeur par défaut aux paramètres si elle n'existe pas. Je refuse que cela soit moins idéal car il se déclenchera sur chaque itinéraire, mais cela peut simplifier vos itinéraires.

{ path: 'user/:userId/agent', redirectTo: '/user/:userId/agent/0', pathMatch: 'full' },
{ path: 'user/:userId/agent/:page', component: AgentListComponent },

Alternative 2 - Vous pouvez encapsuler le HttpClient ou, de préférence, créer une méthode de liste de pages générique qui vérifie cela et l'ajoute à la requête s'il n'y a pas de page. Cette réponse montre un exemple de comment réaliser l'ajout de paramètres.

Alternative 3 strong> - Vous pouvez utiliser la page dans le cadre du chemin et effectuer des contournements / modifications si nécessaire pour générer vos requêtes.

import { Params, RouterStateSnapshot } from '@angular/router';
import { RouterStateSerializer } from '@ngrx/router-store';

export interface RouterStateUrl {
  url: string;
  params: Params;
  queryParams: Params;
}

export class CustomSerializer implements RouterStateSerializer<RouterStateUrl> {
  serialize(routerState: RouterStateSnapshot): RouterStateUrl {
    let route = routerState.root;

    while (route.firstChild) {
      route = route.firstChild;
    }

    const {
      url,
      root: { queryParams },
    } = routerState;
    const { params } = route;

    // Add here
    if (<insert url logic> && queryParams.page === undefined) {
        queryParams.page = 0;
    }

    // Only return an object including the URL, params and query params
    // instead of the entire snapshot
    return { url, params, queryParams };
  }
}


2 commentaires

J'utilise déjà le sérialiseur que vous avez décrit et je n'ai pas pensé à le mettre là-bas. Merci!


Je dois ajouter que queryParams.page = 0 ne fonctionne pas car preventExtensions est vrai. Je l'ai résolu en utilisant un nouvel objet: Object.assign ({}, {page = 0}, queryParams);



1
votes

Dans notre application Angular-7, nous utilisons @ngrx et @ ngrx / router-store pour obtenir les paramètres de requête dans l'état.

Pour synchroniser les paramètres de requête et l'état, vous avez besoin d'un effet qui capture toute action qui entraîne un changement de page dans votre application. À l'intérieur de l'événement, vous aurez quelque chose comme:

export function initStateFromQueryParams(
    reducer: ActionReducer<AppState>
): ActionReducer<AppState> {
    return function(state, action) {
        const newState = reducer(state, action);
        if ([INIT.toString(), UPDATE.toString()].includes(action.type)) {
            const urlParams = new URLSearchParams(window.location.search);
            return { ...newState, page: urlParams.get("page") };
        }
        return newState;
    };
}

Ensuite, un méta-réducteur pour mettre à jour l'état des paramètres de requête lors du rechargement de la page:

@Effect({dispatch:false})
setRouteParams = this.actions$.pipe(
    ofType<ActionCausingPageChange>("action name"),
    tap( action =>{

        let a = { page: action.payload.page };
        // or in case it's not part of action payload, get it from store
        this.router.navigate(
            [], {
                relativeTo: this.route,
                queryParamsHandling: 'merge',
                queryParams: a
            });
        }
    )
);

1 commentaires

Merci pour le lien vers cet article. Ce qui suit m'a fait me demander si la navigation devrait avoir lieu à l'intérieur de l'effet ou à l'extérieur: "Puisque l'utilisateur peut toujours interagir directement avec l'URL, nous devrions traiter le routeur comme la source de vérité et l'initiateur des actions."



0
votes

Pour moi, cela a fonctionné sur le chemin racine:

{
  path: '',
  redirectTo: '/foo?bar=baz',
  pathMatch: 'full'
}

Cependant, en essayant la même chose avec un paramètre nommé (comme votre : userId ) cela ne fonctionne pas


0 commentaires