Angular 6 conflict in router links on same root - javascript

i have two routes :-
1- http://localhost:4200/members/10 ===> this for member's page
2- http://localhost:4200/members/10?tab=3 ===> this for chat page
I want to make chat as a paid service so I create component I called it charge with this route ==> http://localhost:4200/charge so if any member like to go to chat route he will be redirected to charge page as I create code in ngOnInit method in chat component like that
if(!this.authService.paid)
{this.router.navigate(['charge']);}
When I go chat it redirects me to charge page and that's cool , the problem is that when I go member'page it redirects me to charge page and that's not cool at all, so please help me what can i do to solve this problem, thanks in advance
and this is my routes
export const appRoutes: Routes = [
{ path: '', component: HomeComponent },
{
path: '',
runGuardsAndResolvers: 'always'
, canActivate: [AuthGuard],
children: [
{
path: 'members', component: MemberListComponent, resolve: {
users: MemberListResolver
}
},
{
path: 'member/edit', component: MemberEditComponent, resolve: {
user: MemberEditResolver
}, canDeactivate: [PreventUnsavedChangesGuard]
},
{
path: 'members/:id', component: MemberDetailComponent, resolve: {
user: MemberDetailResolver
}
},
{
path: 'lists', component: ListsComponent, resolve: {
users: ListResolver
}
},
{ path: 'messages', component: MessagesComponent, resolve: { messages: MessageResolver }, canActivate: [MessagesGuard] },
{ path: 'charge', component: PaymentComponent }
]
},
{ path: '**', redirectTo: '', pathMatch: 'full' }
];

It looks like you use the same ngOnInit implementation for both pages '/member' and '/chat'. And if this !this.authService.payed returns true, you will always be redirected to '/charge' page.
But to have a better understanding, please provide your routing configuration.
Edit:
Thank you for adding your routes.
{
path: 'members/:id', component: MemberDetailComponent, resolve: {
user: MemberDetailResolver
}
}
It seems like you check for !this.authService.payed in MemberDetailComponent#ngOnInit, but you probably do not check your queryParam ?tab=3.
To fix this issue quickly you can modify your if-condition:
if(!this.authService.payed && this.route.snapshot.queryParams['tab'] === 3)
where this.route has to be injected via constructor parameter
constructor(private route: ActivatedRoute)
But
I think the best solution for this issue would be to add another child route for chat page and handle authorization with another 'canActivate'.

Related

How to fully reload an Angular component only when user is logged in?

In my Angular project I've got:
SignInComponent -> Handling the login requests
DashboardComponent -> Displayed for all children when user has successfully logged in
HomeComponent -> The actual content/page that will be displayed to the user - A child of 'DashboardComponent'
And it looks like:
export const appRoutes: Routes = [
{
path: 'login', component: SignInComponent
},
{
path: '', component: DashboardComponent,
children: [
{ path: '', component: HomeComponent },
],
canActivate: [AuthGuard]
},
{
path: '', redirectTo: '/login', pathMatch: 'prefix'
}
]
Now the problem that I'm facing, is that when the user is successfully logged in, that it won't reload the component 'DashboardComponent'. And I'm not referring to the routes itself (those are going fine). But there's one needed JS script not loaded which blocks the user from expanding the menu item(s). See below:
However, when you manually reload the page, it will work. The menu item(s) will expand. See below:
So, fully reloading the component would do the trick, but I only want that when it's matching with the previous 'route', in this case '/login'. In other words, I would to fully reload the 'DashboardComponent', only when it's not a 'child'. How could I apply this?
Or is there perhaps a better and easier approach?
Here it looks some url match problem because you have defined path:'' to dashboard also making that path to redirect to login with next routing object in routes array
export const appRoutes: Routes = [
{
path: 'login', component: SignInComponent
},
{
path: 'dashboard', component: DashboardComponent,
children: [
{ path: 'home', component: HomeComponent },
],
canActivate: [AuthGuard]
},
{
path: '', redirectTo: '/login', pathMatch: 'prefix'
}
]
So change it like above code and try. This will not make any url confusion and redirection will take place properly
Update:
It seems that custom code (JS) is being called on document ready event. That explains why it's working the only first time. See comment: https://stackoverflow.com/a/46349639/2318669.
What I've done to solve it:
I declared a variable:
declare const openMobileMenu: any;
And then I bind it from the component:
onMobile() {
openMobileMenu();
}
To the following method in the JS file:
function openMobileMenu() {
$(".horizontal-menu .bottom-navbar").toggleClass("header-toggled");
};
Thanks anyway for the support! :)
I appreciate it.

Redirect to Angular internal route from external Application

I am building my authentication system as a different front end application than my dashboard application. The front end auth app is hosted in lets say http://auth.example.net and front end of dashboard app is hosted in http://dashboard.example.net.
Router structure of my dashboard :
{
path: "dashboard",
component: LandingPageComponent,
children: [
{
path: '',
pathMatch: 'full',
redirectTo: 'home'
},
{
path: "home",
component: HomeComponent,
canActivate: [RouteGuard],
data: {
externalUrl: authFrontEnd
}
},
{
path: 'Contact',
component: ContactComponent,
canActivate: [RouteGuard],
data: {
externalUrl: authFrontEnd
}
},
{
path: 'about',
component: AboutComponent,
canActivate: [RouteGuard],
data: {
externalUrl: authFrontEnd
}
}
],
},
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{ path: ":user/:token", component: AuthenticationComponent },
In my auth application, When I am authenticated, I should be redirected to the Dashboard application's url with userId and token embedded in the url (I know its not a secure way to do):http://dashboard.example.net/user_2/token_ec23
In my Auth app:
loginAuthentication(user) {
const result = this.apiService.login(user);
result.subscribe(res=> {
if(res.status === 'success') {
window.location.href=`http://dashboard.example.net/${res.result.user_id}/${res.result.token}`
}
})
}
From what I understand is, this isn't working because the angular routes are only understood inside the angular application. Redirection to angular internal routes can't be happening from external source. How to achieve this thing ? The requirement for me is to pass the token and user Id from auth application to dashboard application and this is the only way I know for now.

Angular : Lazy load multiple Modules with the same route

I have an app where i want to lazy load two modules in the same moment with the same route path.
My routing module would look like this :
{
path: 'mypath',
loadChildren: () => HomeModule,
canLoad: [HomeGuard]
},
{
path: 'mypath',
loadChildren: () => AdvisorModule,
canLoad: [AdvisorGuard]
},
but this lead to load only the first one
i cant' find anyway to do it like this for example :
{
path: 'mypath',
loadChildren: () => HomeModule, advisor module // ??
canLoad: [// ??]
},
I don't want also to import one of them in the other , as like this , only one module would be lazy loaded and the other automatically
How may it do it ??
You could rework things like this:
const routes: Routes = [
{
path: 'mypath/home',
loadChildren: () => HomeModule,
canLoad: [HomeGuard]
},
{
path: 'mypath/advisor',
loadChildren: () => AdvisorModule,
canLoad: [AdvisorGuard]
},
]
In other words move the route path to your module outside to the parent module, in this case I assume those are 'adviser' and 'home'
And then just start in the module routing with a redirect solution and/or a path like so:
Home module routing:
const routes: Routes = [
{
path: '', // <-- in your current solution probably 'home'
component: HomeParentComponent,
children: [
{ path: '', redirectTo: 'childOne', pathMatch: 'full' },
{ path: 'childOne', component: HomeChildComponentOne },
],
},
];
Advisor module routing:
const routes: Routes = [
{
path: '', // <-- in your current solution probably 'advisor'
component: AdvisorParentComponent,
children: [
{ path: '', redirectTo: 'childOne', pathMatch: 'full' },
{ path: 'childOne', component: AdvisorChildComponentOne },
],
},
];
This works nicely, you should be able to navigate to:
'/mypath/home' and end up inside your HomeParentComponent with router outlet of HomeChildComponent one.
'/mypath/advisor' and end up inside your AdvisorParentComponent with router outlet of AdvisorChildComponent one.
In case you don't want a child component inside your router outlet it is even simpler, you can just remove the child routes and redirect.
Note: If this solution doesn't resolve your issue, then please share more details on your module routing so I can get a better picture of your desired route configuration.
You need to re-arrange your routes by one level and you also need to add auxiliary routes for the extra components you want to load.
This works with Angular 9 (probably with 8 too)
{
path: 'home',
component: HostingComponentWithOutlets,
children: [
{
path: 'featureOne',
loadChildren: () => import('xxxxx').then(m => m.FeatureOneModule),
canLoad: [featureOneGuard]
},
{
path: 'featureTwo',
outlet: 'outletAux1',
loadChildren: () => import('yyyyy').then(m => m.FeatureTwoModule),
canLoad: [featureTwoGuard]
},
// you can even load more components to different outlets from the same module
// and update redirectTo and routerLink accordingly
//{
// path: 'featureThree',
// outlet: 'outletAux2',
// loadChildren: () => import('yyyyy').then(m => m.featureTwoModule),
// canLoad: [featureTwoGuard]
//},
{
path: '',
redirectTo:
'/absolute/path/to/home(featureOne/path-to-featureOne-component//outletAux1:featureTwo/path-to-featureTwo-component)',
pathMatch: 'full'
}
]
},
{ path: '', redirectTo: 'home', pathMatch: 'full' }
Hitting the 'home' route will lazy load all required modules.
In your HostingComponentWithOutlets html template where you need to link to 'featureOne':
<a [routerLink]="featureOne/path-to-featureOne-component"
and if you want to go straight to the full route with the auxiliary routes from a template:
<a [routerLink]="['.', { outlets: { 'primary': ['featureOne', 'path-to-featureOne-component'], 'outletAux1': ['featureTwo', 'path-to-featureTwo-component'] } }]"
FeatureOneModule should define 'path-to-featureOne-component' and FeatureTwoModule should define 'path-to-featureTwo-component' in their equivalent route definitions.

Angular 2 RouterStateSnapshot not returning correct url

I'm trying to get the redirect after login working based on the documentation from angular.
https://angular.io/docs/ts/latest/guide/router.html#!#teach-authguard-to-authenticate
I got basically the same setup albeit that some filenames are different.
The problem is that when i log the RouterStateSnapshot url in the authGuard,
it wil always output the first route from app-routing.module.ts ('/countries') instead of e.g. /countries/france/34
authGuard
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url = state.url;
console.log(state); // always outputs first route from app-routing.module.ts ('/countries')
return this.checkLogin(url);
}
checkLogin(url: string): boolean {
if (this.userService.isLoggedIn()) {
return true;
}
this.userService.redirectUrl = url;
console.log(this.userService.redirectUrl);
// not logged in so redirect to login page
this.router.navigate(['/login']);
return false;
}
App routing module
const routes: Routes = [
{ path: '', redirectTo: 'countries', pathMatch: 'full', canActivate: [AuthGuard]},
{ path: 'login', loadChildren: './authentication/authentication.module#AuthenticationModule' },
{ path: 'countries', loadChildren: './countries/countries.module#CountriesModule'},
...
];
Country routing module
const routes: Routes = [
{ path: '', component: CountriesComponent, canActivate: [AuthGuard] },
{ path: ':name/:id', component: CountryComponent, canActivate: [AuthGuard] }
];
Hope someone can help
you are using same AuthGuard for all the paths, hence you are seeing that result, you can either create different Auth guards for different routes or have some logic to identify when the same canActivate is called.
Hope this helps!!

Vue router inherit parent properties

I'm fairly new to vue.js and I'm currently trying to setup my different routes. I'm using sub routes, since the "logged in" user will have a different UI than a visitor.
Currently my setup is like this:
routes: [
{
path: '/auth',
name: 'auth',
component: test,
meta: {
auth: false
},
children: [
{
path: 'login',
name: 'login',
component: login
},
{
path: 'signup',
name: 'signup',
component: signup
}
]
},
{
path: '/user',
name: 'user',
component: test,
meta: {
auth: true
},
children: [
{
path: 'profile',
name: 'profile',
component: login
}
]
}
]
While this is working, I'm wondering why child routes don't take over the parents meta properties. Do I need to assign the meta.auth to each sub route? Or is there any way to inherit this?
Essentially in the router.beforeEach, I want to check if the user is authenticated correctly or not. But only on child routes of /user
I'm also coming from an angular background, so I'm used to nesting routes, not sure if this is the best way in Vue.
To answer my own question: https://github.com/vuejs/vue-router/issues/704
I didn't realise this was deprecated in Vue-router 2.0, it is possible to get the matched route and find the meta there.
With vue-router v.3 to match parent's meta (for example: in beforeEach() func. ) You need to use to.matched.some() like this:
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.auth)) {
// ...
next({name:'route-name'})
} else {
next()
}
}
https://router.vuejs.org/guide/advanced/meta.html

Categories