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 comprendre pleinement (pardonnez le jeu de mots) ce qu'est la correspondance URL-route d'Angular. pathMatch: full
si vous ne savez pas comment fonctionne le routeur.
Définissons d'abord quelques éléments de base. Nous allons utiliser cette URL comme exemple : /users/james/articles?from=134#section
.
-
C'est peut-être évident, mais soulignons d'abord que paramètres d'interrogation ( ?from=134
) et des fragments ( #section
) ne jouent aucun rôle dans la correspondance des chemins . Seule l'url de base ( /users/james/articles
) est important.
-
Angular divise les URLs en segments . Les segments de /users/james/articles
sont, bien sûr, users
, james
y articles
.
-
La configuration du routeur est un arbre avec un seul nœud racine. Chaque Route
est un nœud, qui peut avoir children
qui peuvent à leur tour avoir d'autres children
ou être des nœuds feuilles.
Le but du routeur est de trouver une configuration de routeur branche en commençant par le nœud racine, ce qui correspondrait à exactement tout ( !!!) des segments de l'URL. C'est crucial ! Si Angular ne trouve pas de branche de configuration de route qui pourrait correspondre à l'élément ensemble du site URL - ni plus ni moins - il ne rendra pas tout ce qui est .
Par exemple, si votre URL cible est /a/b/c
mais le routeur ne peut correspondre qu'à l'un ou l'autre des éléments suivants /a/b
o /a/b/c/d
alors il n'y a pas de correspondance et l'application ne rendra rien.
Enfin, les routes avec redirectTo
se comporter légèrement différemment des routes régulières, et il me semble que ce serait le seul endroit où quelqu'un voudrait vraiment utiliser pathMatch: full
. Mais nous y reviendrons plus tard.
Par défaut ( prefix
) correspondance des chemins
La raison d'être du nom prefix
c'est qu'une telle configuration de route vérifiera si la route configurée path
est un préfixe des segments d'URL restants. Cependant, le routeur est seulement capable de faire correspondre segments complets ce qui rend cette dénomination légèrement confuse.
Quoi qu'il en soit, disons qu'il s'agit de notre configuration de routeur au niveau de la 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
utilise ici la stratégie de correspondance par défaut, qui est prefix
. Cette stratégie signifie que le routeur itère sur l'ensemble de l'arbre de configuration et essaie de le faire correspondre à l'URL cible. segment par segment jusqu'à ce que l'URL soit parfaitement adaptés . Voici comment procéder pour cet exemple :
- Itérer sur le tableau Root à la recherche d'une correspondance exacte pour le premier segment d'URL.
users
.
-
'products' !== 'users'
alors sautez cette branche. Notez que nous utilisons une vérification de l'égalité plutôt qu'une vérification de l'existence d'une .startsWith()
o .includes()
- seuls les matches à segment complet comptent !
-
:other
correspond à n'importe quelle valeur, donc c'est une correspondance. Cependant, l'URL cible n'a pas encore été entièrement trouvée (nous devons encore trouver une correspondance avec la valeur james
y articles
), le routeur recherche donc les enfants.
- L'unique enfant de
:other
es tricks
que es !== 'james'
donc pas de correspondance.
- Angular revient ensuite au tableau Root et continue à partir de là.
-
'user' !== 'users
, sauter la branche.
-
'users' === 'users
- le segment correspond. Cependant, il ne s'agit pas encore d'une correspondance complète, nous devons donc rechercher les enfants (comme à l'étape 3).
-
'permissions' !== 'james'
passez votre chemin.
-
:userID
correspond à n'importe quoi, donc nous avons une correspondance pour l'élément james
segment. Toutefois, il s'agit toujours pas une correspondance complète, donc nous devons chercher un enfant qui correspondrait à articles
.
- On peut voir que
:userID
a une route enfant articles
ce qui nous donne une correspondance complète ! Ainsi l'application rend UserArticlesComponent
.
URL complet ( full
) correspondant
Exemple 1
Imaginez maintenant que le users
L'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 c'était le cas, les étapes 1 à 5 seraient les mêmes, mais l'étape 6 serait différente :
-
'users' !== 'users/james/articles
- le segment fait no correspondent parce que la configuration du chemin users
avec pathMatch: full
ne correspond pas à l'URL complète, qui est users/james/articles
.
- Comme 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 rend rien .
Exemple 2
Et si on avait ça à la place :
{
path: 'users/:userID',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
}
users/:userID
avec pathMatch: full
ne correspond qu'à users/james
Il n'y a donc pas de correspondance, une fois de plus, 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ée. Cherchons des enfants.
-
'permissions' !== 'james'
- sauter.
-
:userID'
ne peut correspondre qu'à un seul segment, ce qui serait james
. Cependant, c'est un pathMatch: full
et il doit correspondre à james/articles
(toute l'URL restante). Il n'est pas capable de faire cela et donc ce n'est pas une correspondance (donc nous sautons cette branche) !
- Encore une fois, nous n'avons pas réussi à trouver de correspondance pour l'URL et l'application rendra rien .
Comme vous l'avez peut-être remarqué, un pathMatch: full
Ignorez mes enfants et n'affrontez que moi. Si je ne suis pas en mesure de correspondre à tous les restant Je me segmente en URL, puis je passe à autre chose.
Redirections
Tout Route
qui a défini un redirectTo
seront comparés à 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 l'adresse par défaut de l'utilisateur. prefix
stratégie, une une correspondance partielle est suffisante pour 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'
- sautez-la.
-
'users' === 'users'
- nous avons une correspondance.
- Ce match a un
redirectTo: 'not-found'
que es appliqué immédiatement .
- L'URL cible devient
not-found
.
- Le routeur recommence à chercher des correspondances et trouve une correspondance pour
not-found
tout de suite. L'application rend NotFoundComponent
.
Maintenant, considérez ce qui se passerait si le users
La route 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'
- sautez-la.
-
users
correspondrait au premier segment de l'URL, mais la configuration de l'itinéraire exige un full
correspond, donc passez-le.
-
'users/:userID'
correspond à users/james
. articles
ne correspond toujours pas mais cette route a des enfants.
- Nous trouvons une correspondance pour
articles
dans les enfants. L'ensemble de l'URL est maintenant apparié et l'application effectue le rendu suivant UserArticlesComponent
.
Chemin vide ( path: ''
)
Le chemin vide est un cas un peu particulier car il peut correspondre à cualquier segment sans le "consommer" (de sorte que 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 la route correspondra. Cependant, la totalité de l'URL n'a pas été trouvée - nous devons encore trouver une correspondance avec les éléments suivants users
!
- Nous pouvons voir qu'il y a un enfant
users
qui correspond au segment restant (et le seul !) 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 va résoudre ce problème :
-
welcome
ne correspond pas à un segment vide, il est donc ignoré.
-
path: ''
correspond au segment vide. Il a un pathMatch: 'full'
ce qui est également satisfaisant car nous avons fait correspondre l'URL entière (elle avait un seul segment vide).
- Une redirection vers
welcome
se produit et l'application rend WelcomeComponent
.
Et s'il n'y avait pas pathMatch: 'full'
?
En fait, on s'attendrait à ce que l'ensemble se comporte exactement de la même manière. Cependant, Angular empêche explicitement une telle configuration ( { path: '', redirectTo: 'welcome' }
) parce que si vous mettez ce Route
au-dessus de welcome
cela créerait théoriquement une boucle sans fin de redirections. Donc Angular a juste lance une erreur C'est pourquoi l'application ne fonctionne pas du tout ! ( https://angular.io/api/router/Route#pathMatch )
En fait, cela n'a pas beaucoup de sens pour moi car Angular également a mis en place une protection contre ces redirections sans fin : il n'exécute qu'une seule redirection par niveau de routage ! Cela permet d'arrêter toutes les autres redirections (comme vous le verrez dans l'exemple ci-dessous).
Qu'en est-il path: '**'
?
`path: ''** correspondra à **absolument tout** ( **
af/frewf/321532152/fsa** est une correspondance) avec ou sans un **
pathMatch: 'full'`** .
De plus, comme il correspond à tout, le chemin de la racine est également inclus, ce qui fait que { path: '', redirectTo: 'welcome' }
complètement redondant dans cette configuration.
Il est amusant de constater que cette configuration est parfaitement acceptable :
const routes: Routes = [
{
path: '**',
redirectTo: 'welcome'
},
{
path: 'welcome',
component: WelcomeComponent,
},
];
Si nous naviguons vers /welcome
, `path: ''`** correspondra et une redirection vers l'accueil se produira. Théoriquement, cela devrait déclencher une boucle sans fin de redirections, mais Angular l'arrête immédiatement (grâce à la protection que j'ai mentionnée précédemment) et l'ensemble fonctionne parfaitement.