Bien que techniquement correctes, les autres réponses bénéficieraient d'une explication de la correspondance URL-route d'Angular. Je ne pense pas que vous puissiez pleinement (pardonnez le jeu de mots) comprendre ce qui se pathMatch: full
passe si vous ne savez pas comment le routeur fonctionne en premier lieu.
Définissons d'abord quelques éléments de base. Nous allons utiliser cette URL comme exemple: /users/james/articles?from=134#section
.
Cela peut être évident, mais soulignons d'abord que les paramètres de requête ( ?from=134
) et fragments ( #section
) ne jouent aucun rôle dans la correspondance de chemin . Seule l'url de base ( /users/james/articles
) compte.
Angular divise les URL en segments . Les segments de /users/james/articles
sont, bien sûr users
, james
et articles
.
La configuration du routeur est une arborescence avec un seul nœud racine. Chaque Route
objet est un nœud, qui peut avoir des children
nœuds, qui peuvent à leur tour en avoir d'autres children
ou être des nœuds feuilles.
Le but du routeur est de trouver une branche de configuration du routeur , en commençant par le nœud racine, qui correspondrait exactement à tous les segments (!!!) de l'URL. C'est crucial! Si Angular ne trouve pas de branche de configuration d'itinéraire qui pourrait correspondre à l' URL entière - ni plus ni moins - il ne rendra rien .
Par exemple, si votre URL cible est /a/b/c
mais que le routeur ne peut correspondre qu'à l'un /a/b
ou l' autre /a/b/c/d
, alors il n'y a pas de correspondance et l'application ne rendra rien.
Enfin, les itinéraires avec redirectTo
se comportent légèrement différemment des itinéraires réguliers, et il me semble qu'ils seraient le seul endroit où quiconque voudrait vraiment utiliserpathMatch: full
. Mais nous y reviendrons plus tard.
prefix
Correspondance de chemin par défaut ( )
Le raisonnement derrière le nom prefix
est qu'une telle configuration d'itinéraire vérifiera si le configuré path
est un préfixe des segments d'URL restants. Cependant, le routeur ne peut faire correspondre que des segments complets , ce qui rend cette dénomination légèrement confuse.
Quoi qu'il en soit, disons que c'est notre configuration de routeur au niveau racine:
const routes: Routes = [
{
path: 'products',
children: [
{
path: ':productID',
component: ProductComponent,
},
],
},
{
path: ':other',
children: [
{
path: 'tricks',
component: TricksComponent,
},
],
},
{
path: 'user',
component: UsersonComponent,
},
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
},
];
Notez que chaque Route
objet utilise ici la stratégie de correspondance par défaut, qui est prefix
. Cette stratégie signifie que le routeur effectue une itération sur l'ensemble de l'arborescence de configuration et essaie de la comparer à l'URL cible segment par segment jusqu'à ce que l'URL soit entièrement mise en correspondance . Voici comment cela serait fait pour cet exemple:
- Parcourez le tableau racine à la recherche d'une correspondance exacte pour le premier segment d'URL -
users
.
'products' !== 'users'
, alors sautez cette branche. Notez que nous utilisons un contrôle d'égalité plutôt qu'un .startsWith()
ou .includes()
- seuls les segments complets comptent!
:other
correspond à n'importe quelle valeur, donc c'est une correspondance. Cependant, l'URL cible n'est pas encore entièrement appariée (nous devons encore faire correspondre james
et articles
), le routeur recherche donc des enfants.
- Le seul enfant de
:other
est tricks
, qui n'est !== 'james'
donc pas une correspondance.
- Angular revient ensuite au tableau racine et continue à partir de là.
'user' !== 'users
, sauter la branche.
'users' === 'users
- le segment correspond. Cependant, ce n'est pas encore une correspondance complète, nous devons donc rechercher des enfants (comme à l'étape 3).
'permissions' !== 'james'
, sauter.
:userID
correspond à tout, nous avons donc une correspondance pour le james
segment. Cependant, ce n'est toujours pas une correspondance complète, nous devons donc rechercher un enfant qui correspondrait articles
.
- Nous pouvons voir qu'il
:userID
a une route enfant articles
, ce qui nous donne une correspondance complète! Ainsi, l'application rend UserArticlesComponent
.
full
Correspondance URL complète ( )
Exemple 1
Imaginez maintenant que l' users
objet de configuration de la route ressemblait à ceci:
{
path: 'users',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
Notez l'utilisation de pathMatch: full
. Si tel était le cas, les étapes 1 à 5 seraient les mêmes, mais l'étape 6 serait différente:
'users' !== 'users/james/articles
- le segment ne correspond pas car la configuration du chemin users
avec pathMatch: full
ne correspond pas à l'URL complète, qui est users/james/articles
.
- Puisqu'il n'y a pas de correspondance, nous sautons cette branche.
- À ce stade, nous avons atteint la fin de la configuration du routeur sans avoir trouvé de correspondance. L'application ne rend rien .
Exemple 2
Et si nous avions ceci à la place:
{
path: 'users/:userID',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
}
users/:userID
avec des pathMatch: full
allumettes seulementusers/james
, c'est donc à nouveau une non-correspondance, et l'application ne rend rien.
Exemple 3
Considérons ceci:
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
Dans ce cas:
'users' === 'users
- le segment correspond, mais james/articles
reste toujours inégalé. Cherchons des enfants.
'permissions' !== 'james'
- sauter.
:userID'
ne peut correspondre qu'à un seul segment, ce qui serait james
. Cependant, c'est une pathMatch: full
route, et elle doit correspondre james/articles
(toute l'URL restante). Ce n'est pas capable de faire ça et donc ce n'est pas un match (donc on saute cette branche)!
- Encore une fois, nous n'avons trouvé aucune correspondance pour l'URL et l'application ne rend rien .
Comme vous l'avez peut-être remarqué, une pathMatch: full
configuration dit essentiellement ceci:
Ignorez mes enfants et ne me correspond. Si je ne parviens pas à faire correspondre moi-même tous les segments d'URL restants , passez à autre chose.
Redirige
Tout Route
ce qui a défini un redirectTo
sera comparé à l'URL cible selon les mêmes principes. La seule différence ici est que la redirection est appliquée dès qu'un segment correspond . Cela signifie que si une route de redirection utilise la prefix
stratégie par défaut , une correspondance partielle suffit à provoquer une redirection . Voici un bon exemple:
const routes: Routes = [
{
path: 'not-found',
component: NotFoundComponent,
},
{
path: 'users',
redirectTo: 'not-found',
},
{
path: 'users/:userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
];
Pour notre URL initiale ( /users/james/articles
), voici ce qui se passerait:
'not-found' !== 'users'
- sauter.
'users' === 'users'
- nous avons un match.
- Cette correspondance a un
redirectTo: 'not-found'
, qui est appliqué immédiatement .
- L'URL cible devient
not-found
.
- Le routeur recommence à correspondre et trouve
not-found
immédiatement une correspondance. L'application rend NotFoundComponent
.
Considérez maintenant ce qui se passerait si l' users
itinéraire avait également pathMatch: full
:
const routes: Routes = [
{
path: 'not-found',
component: NotFoundComponent,
},
{
path: 'users',
pathMatch: 'full',
redirectTo: 'not-found',
},
{
path: 'users/:userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
];
'not-found' !== 'users'
- sauter.
users
correspondrait au premier segment de l'URL, mais la configuration de l'itinéraire nécessite une full
correspondance, donc ignorez-la.
'users/:userID'
matchs users/james
. articles
ne correspond toujours pas mais cet itinéraire a des enfants.
- Nous trouvons un match pour
articles
les enfants. L'URL entière est maintenant mise en correspondance et l'application est rendue UserArticlesComponent
.
Chemin vide ( path: ''
)
Le chemin vide est un peu un cas particulier car il peut correspondre à n'importe quel segment sans le «consommer» (donc ses enfants devraient à nouveau correspondre à ce segment). Prenons cet exemple:
const routes: Routes = [
{
path: '',
children: [
{
path: 'users',
component: BadUsersComponent,
}
]
},
{
path: 'users',
component: GoodUsersComponent,
},
];
Disons que nous essayons d'accéder /users
:
path: ''
correspondra toujours, donc l'itinéraire correspond. Cependant, toute l'URL n'a pas été mise en correspondance - nous devons encore faire correspondre users
!
- Nous pouvons voir qu'il y a un enfant
users
, qui correspond au segment restant (et seulement!) Et nous avons une correspondance complète. L'application rend BadUsersComponent
.
Revenons maintenant à la question initiale
L'OP a utilisé cette configuration de routeur:
const routes: Routes = [
{
path: 'welcome',
component: WelcomeComponent,
},
{
path: '',
redirectTo: 'welcome',
pathMatch: 'full',
},
{
path: '**',
redirectTo: 'welcome',
pathMatch: 'full',
},
];
Si nous naviguons vers l'URL racine ( /
), voici comment le routeur résoudrait cela:
welcome
ne correspond pas à un segment vide, alors ignorez-le.
path: ''
correspond au segment vide. Il a un pathMatch: 'full'
, qui est également satisfait car nous avons fait correspondre l'URL entière (il y avait un seul segment vide).
- Une redirection se
welcome
produit et l'application s'affiche WelcomeComponent
.
Et s'il n'y avait pas pathMatch: 'full'
?
En fait, on s'attendrait à ce que tout se comporte exactement de la même manière. Cependant, Angular empêche explicitement une telle configuration ( { path: '', redirectTo: 'welcome' }
) car si vous mettez cela Route
ci - dessus welcome
, cela créerait théoriquement une boucle sans fin de redirections. Donc Angular jette juste une erreur , c'est pourquoi l'application ne fonctionnerait pas du tout! ( https://angular.io/api/router/Route#pathMatch )
Cela n'a vraiment pas trop de sens car Angular a implémenté une protection contre les redirections sans fin - il n'exécute qu'une seule redirection par niveau de routage.
Et quoi path: '**'
?
path: '**'
correspondra absolument à tout ( af/frewf/321532152/fsa
est une correspondance) avec ou sans a pathMatch: 'full'
, il est donc inutile d'utiliser cette option de configuration.
De plus, comme il correspond à tout, le chemin racine est également inclus, ce qui rend { path: '', redirectTo: 'welcome' }
redondant dans cette configuration.
Curieusement, c'est parfaitement bien d'avoir cette configuration:
const routes: Routes = [
{
path: '**',
redirectTo: 'welcome'
},
{
path: 'welcome',
component: WelcomeComponent,
},
];
Si nous naviguons vers /welcome
, il y path: '**'
aura un match et une redirection vers la bienvenue se produira. Cela devrait lancer une boucle sans fin de redirections, mais Angular arrête cela immédiatement et tout fonctionne bien.