I have the following routes variable defined in my app-routing.module.ts:
const routes: Routes =
[
{ path: '', redirectTo: '/users', pathMatch: 'full' },
{ path: 'users', component: UsersComponent },
{ path: 'dashboard', component: DashboardComponent }
];
With this current configuration, when I submit http://localhost:3000/users, the browser redirects to http://localhost:3000/users/users and then displays the user list binding in the html as expected.
However, something seems off kilter for the browser to redirect from /users to /users/users. If I remove the th first route config with the redirectTo attribute then the browser stays on /users without redirecting to /users/users. However, in this scenario, the user list binding doesn't display as expected.
Any idea what might be causing the redirect to /users/users? Any idea how I can keep the browser on /users and get the user list binding to properly display at this uri?
Option 1: Setting base tag
In order to get the router working properly a base href needs to be defined somehow for the app. The docs recommend adding a base element to the head of your index.html file, such as:
<base href="/">
Option 2: Setting a provider
This can be a bit dangerous however as it has (potentially unexpected) side effects on anchor tags, empty href tags, etc, etc. It also breaks inline svg sprites... which was a major part of our app's UI. If you want to make the router work but not break a lot of things you can actually define the base href elsewhere, like so:
// ... other imports
import { APP_BASE_HREF } from '#angular/common';
#NgModule({
// ... other pieces of ngModule
providers: [
{provide: APP_BASE_HREF, useValue : '/' }
],
// ... other pieces of ngModule
})
export class AppModule {
constructor() {}
}
As a basic example. It's a bit hard to find in the documentation but is a good workaround to get things going without messing with everything else.
Related
I'm new in Angular but I came from various frameworks that are relevant to the Backend such as Django, I note that Angular has the same nature as Django routing a bit regardless that it belongs to client-side so, so I'm familiar with routing confused around how Angular handles routing and use router-link in the template in Angular.
there is my problem:
export const routes: Routes = [
{path: 'login', component: LoginComponent, outlet: "login"},
{path: 'signup', component: RegisterComponent, outlet: "register"},
]
when I'm trying to move to the login page by the following statement:
<a [routerLink]="['', {outlets: {login: ['login']}}]" ariaCurrentWhenActive="page" routerLinkActive="active">Signin?</a>
what is happening is that the link looks like this link when it displaying it in the inspect element:
/app/(login:login//register:signup)
my current page is /app/(register:signup) and all I want to do is to move to: /app/(login:login)
first of all, I want to know how to move to my target.
second: I want to understand the router link nature in angular and how it works if it is possible.
Say I have 2 routes '/users' and /users/:id. First one renders UserListComponent and second UserViewComponent.
I want to re-render component when navigating from /users/1 to /users/2. And of course if I navigate from /users to /users/1 and vice versa.
But I DON'T want to re-render component if I navigate from /users/1?tab=contacts to /users/1?tab=accounts.
Is there a way to configure router like this for entire application?
--
Update:
I'm importing RouterModule in AppRoutingModule like this:
RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })
I'm using Angular 12
The default behavior of the Angular router is to preserve the current component when the URL matches the current route.
This behavior can be changed by using the onSameUrlNavigation option:
Define what the router should do if it receives a navigation request
to the current URL. Default is ignore, which causes the router ignores
the navigation. This can disable features such as a "refresh" button.
Use this option to configure the behavior when navigating to the
current URL. Default is 'ignore'.
Unfortunately, this option is not fine-grained enough to allow reload for path params and ignore for query params.
So you have to subscribe both to the query params and the path params changes with something like this:
constructor(route: ActivatedRoute) { }
ngOnInit() {
this.renderLogic();
this.route.params.subscribe(() => this.renderLogic());
this.route.queryParams.subscribe(() => this.renderLogic());
}
renderLogic() {
// ...
}
As far as I know, #Guerric P is correct, you can't completely re-render the component selectively like this, at least not without some trickery like subscribing to each event and then possibly blocking it for one scenario and not the other. Feel free to try something like that, but below is an alternative if you make use of resolvers to fetch your data.
What you can do is use runGuardsAndResolvers in your route configuration like so:
const routes = [{
path: 'team/:id',
component: Team,
children: [{
path: 'user/:name',
component: User
}],
runGuardsAndResolvers: 'pathParamsChange',
resolvers: {...},
canActivate: [...]
}]
This will, as the name suggests, run your guard resolver logic again. If you fetch data using resolvers and pass it into your components, you can update what your component displays only when the path or params change.
I'm trying to catch routing exceptions in my app. Basically there are 3 ways a user can navigate:
Typing the address - catching that is easy just { path: '**', redirectTo: 'errorPage'} in the route config.
The code called router.navigate(['pageName']) - catching that is easy too: .then(res => res, error => {
//service to log error to server
router.navigate(['errorPage']);
});
Clicking an HTML element that has [routerLink]="somePath" attribute.
It's the third one that I don't know how to catch.
Presumably such an error could occur if the module didn't load for some reason. I need to be able to handle that (and other unforeseen events) gracefully.
TO CLARIFY
The wildcard definition works for router problems, in most cases. But here's the thing, what if there is a route defined earlier in the configuration, but it leads to a module that can't be found! (I actually had this error in develop, which is why I am aware that it can happen, we're using lazy loading, and it happened that with some network problems a required module didn't load). The router finds a route, and tries to resolve it, but can't because the module, for whatever reason, did not load. The wildcard definition doesn't help here, because the router found a path but can't reach it. So it throws an error, which I'm trying to catch. Because for some reason router errors choke the whole app.
Why not create fallback path in routing module?
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: '**', component: NotFoundComponent },
];
When user enter not existing url will be redirected to NotFoundComponent.
This { path: '**', redirectTo: 'errorPage'} is what is called the wildcard route definition, which Angular official doc defines as:
The router will select this route if the requested URL doesn't match any paths for routes defined earlier in the configuration. This is useful for displaying a "404 - Not Found" page or redirecting to another route.
So this should work for any case when the requested route doesn't match any of the defined routes (doesn't matter if it was typed or set). Check if the routerLink definition is correct because the definition for it is without the brackets: <a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
In AngularJS, for routing purposes, we define states with children which makes it possible to switch between views with the result that each view is always rendered in one container:
$stateProvider.state("communication.create-message", {
url: ...,
templateUrl: ...,
menu: ...,
parent: "communication",
ncyBreadcrumb: {
label: "Create Message"
}
});
Whichever state we choose - the view is always rendered within one container that has ui-view attribute.
I'm trying to achieve the same in Angular 2 or above, but I have no idea of how to reproduce the above-stated functionality.
In app.component.ts we have router-outlet where component templates get rendered.
Say, we have many nested child routes - is it possible to render all of them within this outlet ?
What would the code in app-routing.module.ts look like in this case ?
Could anyone please give a working example of how to go about it ?
Step 1 : Import Routes from #angular/router
in app.module.ts .. import Routes. You have to write
import {Routes} from '#angular/core'
Step 2 :
Add all the routes you want to set up in an array pf type Routes like :
this is for informing angular all the routes in your app. Each route is a javascript object in this array.
const appRoutes : Routes = [
{path : 'communication-route'}
]
always you have to give path , this what you enter after your domain like "localhost :4200/communication-route".
Step 3: Add the action to route i.e what happens when this path is reached.
const appRoutes : Routes = [
{path : 'communication-route'} , component :communicationroutecomponent
]
here i have given the component name "communicationroutecomponent" , i.e this component will be loaded when the path "/communication-route" is reached
Step 4: Register your routes in your app
To do this you will have to do new import in app.module.ts
import {RouterModule} from '#angular/router'
Routermodule has special method forRoot() which registers our routes .
In our case we will have to write this piece of code in
imports :[
RouterModule.forRoot(appRoutes)
]
Our routes are now registered and angular knows our routes now.
Step 5 : Where to display the route content i.e the html content of you route page.
For this angular has directive .
We need to include where we want to load our content i.e in the html.
<a router-outlet="/communication-route"></a>
Navigating to routes :
angular gives a directive for this routerLink
so if we want to navigate to users component , you can give this in your html element:
routerLink="/communication-route"
I hope i was able to explain how this works.
Your code should be as follows
export const ComRoute: Routes = [
{
path: 'communication-route',
children: [
{ path: 'communication', component: communicationComponent },
{ path: ':child1', component: child1Component },
{ path: ':child1/field', component: child1Component}
]
}
];
First of all, states are not an official AngularJS concept. They come from ui-router, which began life as an alternate to the simplistic built in router.
Eventually, ui-router became the de facto standard for routing in AngularJS while the official ng-route module was extracted into a separate, optional library by the Angular team.
ui-router, is complex but exceptional and has earned what is in my view well deserved popularity and success. This success has led to its expansion to support additional platforms enabling the same powerful state based structure in applications written for frameworks such as React.
It is now available for Angular (formerly known as Angular 2).
You can read the documentation and see how to get started on https://ui-router.github.io/ng2
Here is a snippet from the src/app/app.states.ts module of the official example repository
export const loginState = {
parent: 'app',
name: 'login',
url: '/login',
component: LoginComponent,
resolve: [
{ token: 'returnTo', deps: [Transition], resolveFn: returnTo },
]
};
As we can see, there are compatible concepts available, including what looks like a nice evolution of the resolves API which allows function oriented injection which was generally simpler than class based injection in ui-router with AngularJS.
Note, I have not used it in an Angular project.
With Angular 2, I could make a child route render "over" its parent by defining an empty path and creating an essentially empty base component. I am trying to accomplish something similar with the new Angular router (version 4.3.1), but have hit a roadblock.
To reproduce my problem, here's a Plunker. The routes are defined as:
[{
path: '',
redirectTo: "/master",
pathMatch: "full"
}, {
path: 'master',
component: MasterComponent,
children: [{
path: 'detail/:value',
component: DetailComponent,
children: [{
path: 'subdetail',
component: SubDetailComponent
}]
}]
}]
When I navigate to a detail page, the master page is still visible because I have added a <router-outlet></router-outlet> to MasterComponent. What I need is to replace the master view with the detail. I can accomplish this by making detail/:value a sibling of master rather than a child, but this isn't logically correct in my application and breaks my breadcrumbs.
Is there any proper way to handle this kind of pattern, or will I have to pick a workaround, such as showing and hiding the intended route or manually specifying a dedicated "main" outlet for every link?
The only existing solution that comes close is to define a dummy parent component, but this only works one-level down. If my detail page has another sub-detail page that should also replace master, it gets very messy.
Is there any route-level flag I can set or design pattern to implement to elegantly accomplish this? I am an Angular 2 beginner, but I feel as though something like this should be simple.
First, there is no "new" router in 4.3.1. It's the same router from 2.x.
Second, there were a few changes I needed to make to your plunker to make it work appropriately. The key change was this in the master.component.ts:
<a [routerLink]="['/detail', 5]">
I added a slash. Without the slash it was looking for a route named master/detail/5
The route definition is now flat, so everything will appear "under" your main header.
export const routes: Routes = [
{
path: '',
redirectTo: 'master',
pathMatch: 'full'
},
{
path: 'master',
component: MasterComponent
},
{
path: 'detail/:value',
component: DetailComponent
}
];
The updated plunker is here: https://plnkr.co/edit/EHehUR6qSi248vQPDntt?p=preview