I'm creating an app that when the user enters to the page he goes to the default route wich is "Login" page. What I want is based on a condition (if the user has a local storage variable id, a method called isAuthenticaded() returns true if not false) the user must see the "Polls" page instead of "Login" page.
I think two different ways to aprouch this:
1- Change default page: if the method returns true the default page should be "Polls" if not "Login".
2- Redirect the user: if the method returns true the user is redirected to "Polls".
What's the best aprouch to archieve this?
How can I do one or both of the point to get conditional routing?
This is my routing config with the isAuthenticated() method:
import {Component} from 'angular2/core'
import {HTTP_PROVIDERS, Http} from 'angular2/http';
import 'rxjs/Rx'; // load the full rxjs
import {RouteConfig, ROUTER_DIRECTIVES, Router} from 'angular2/router';
import { PollsComponent } from './pollslist/pollslist.component'
import { Login } from './login/login'
#Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
directives: [ROUTER_DIRECTIVES, Login, PollsComponent],
providers: [HTTP_PROVIDERS]
})
#RouteConfig([
{ path: '/login', name: 'Login', component: Login, useAsDefault: true },
{ path: '/polls', name: 'Polls', component: PollsComponent }
])
export class AppComponent {
isAuthenticated() {
if (localStorage.getItem('id')) {
return true;
} else {
return false;
}
}
}
You can check in
#CanActivate() and navigate to a different route using router.navigate()
or create a custom <router-outlet> where you do this.
For details see https://medium.com/#blacksonic86/authentication-in-angular-2-958052c64492#.f76jyafdn
See also Check if the user logged in on any page change in Angular 2
Router definition has loader parameter:
loader : () => Promise<Type>
that allows to determine component type dynamically and async.
Related
I have already implemented ngx-translate succesfully. Now, I want to change the base href of my Angular project, depending on the language I choose from my header menu.
Currently, my URL looks like this: "localhost:4200". Then, when you launch the project, it must show something like this: "localhost:4200/en" or like this: "localhost:4200/es", depending on the choosen language.
My index html has this:
<base href="/"/>
And my header component ts file has a function that changes the language using ngx-translate. As you can see, I tried to use 'replaceState' to show the choosen language in the URL, and it worked, but it disappears once I navigate to another route.
import { Component, OnInit } from '#angular/core';
//For translate language
import { TranslateService } from '#ngx-translate/core';
import { Router, Event, NavigationStart, NavigationEnd } from '#angular/router';
import { Location } from '#angular/common';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent implements OnInit {
constructor(private translate: TranslateService,
private router: Router,
private location: Location,
)
{ translate.addLangs(['es','en']);
translate.setDefaultLang('es');
}
ngOnInit(): void {
}
useLanguage(language: string): void {
this.translate.use(language);
// alert(language);
// location.replace("https://www.google.com");
// return;
const modified_path = language;
this.location.replaceState(modified_path);
}
}
It looks like you are trying to achieve some kind of routing using base href. I would use base href only if I need multiple instances of my application. E.g. each of them in a subfolder.
Maybe you should give try on Angular Router (https://angular.io/guide/router-reference) if you want just one instance of the application handling different languages.
The idea is to have a route on the root level that represents the language and a language guard that ensures only valid languages are called.
This would look something like this:
const routes2: Routes = [
{
path: ':language',
canActivate: [LanguageGuard],
children: [
{
path: 'home',
component: HomeComponent,
},
{
path: 'some-page',
component: SomePageComponent,
},
]
},
{
path: '**',
redirectTo: '/en',
},
];
I have route configuration set up via #NgModule. And I have a service that identifies what parts of the application should be shown for the user depending on certain conditions. I need to call that service and setup the routes according to the returned value.
Problem: Route configuration is setup inside an annotation and I can't get how to call the service in such setup.
To be more specific here is the example configuration I want to enhance.
My current routing setup:
const appRoutes: Routes = [
{
path: '',
redirectTo: 'first-route',
pathMatch: 'full'
},
{
path: 'first-route',
component: FirstComponent,
pathMatch: 'full'
},
{
path: 'second-route',
component: SecondComponent,
pathMatch: 'full'
},
...
];
#NgModule({
imports: [RouterModule.forChild(appRoutes)],
exports: [RouterModule]
})
export class MyRoutingModule {
}
The service that should change the route setup:
#Injectable()
export class MyService {
getAccessibleRoutes(): Observable<string[]> {...}
}
Question: How can I make a service call and change the routes?
Note: I also looked on "Dynamically adding routes in Angular" and "How we can add new routes dynamically into RouterModule(#NgModule imports)" but I haven't found clear answer there.
If I correctly understood your problem, I think you probably can consider using route guards to reach you goal. I suggest you to use guards feature to specify the conditions of accessing your routes, instead of changing the list of routes.
Please check this link for more information about route guards:
https://codecraft.tv/courses/angular/routing/router-guards/
I hope this will help you.
import { Injectable } from '#angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { YourSecurityService } from './your-security.service';
#Injectable()
export class YourRouteGuardService implements CanActivate {
constructor(
private router: Router,
private yourSecurityService: YourSecurityService) {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
console.log(state.url); // HERE YOU CAN GET REQUESTED ROUTE
if (this.yourSecurityService.checkIfUserHaveAccess())
return true;
this.router.navigate(['your-route-to-redirect']);
return false;
}
}
Next you should apply your guard to your route:
const appRoutes: Routes = [
{
path: 'someroute',
component: RouteComponent,
canActivate: [YourRouteGuardService]
},
...
]
I've a small question regarding Angular 2 router using version 3.0.0-rc.1 I want to navigate to different home component based on user role such as AdminComponent or UserComponent. Can anyone please help in modifying below routes so that I can achieve the desired functionality?
{path: 'login', component: LoginComponent}, // <--- This redirects to '/' in case user is logged in
{
path: '',
component: HomeComponent,
canActivate: [AuthGuardService], // <--- Check if user is logged in, else redirect to login
children: [
{
path: '',
component: AdminComponent // <--- Want to navigate here if user role is 'admin'
},
{
path: '',
component: UserComponent // <--- Want to navigate here if user role is 'user'
}
]
}
AuthGuardService.ts
import {Injectable} from "#angular/core";
import {CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot} from "#angular/router";
import {AuthService} from "./auth.service";
#Injectable()
export class AuthGuardService implements CanActivate {
constructor(private authService: AuthService, private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.authService.isLoggedIn()) {
return true;
}
// Store the attempted URL for redirecting
this.authService.redirectUrl = state.url;
// Navigate to the login page with extras
this.router.navigate(['/login']);
return false;
}
}
AuthService.ts
import {Injectable} from "#angular/core";
#Injectable()
export class AuthService {
redirectUrl: string;
logout() {
localStorage.clear();
}
isLoggedIn() {
return localStorage.getItem('token') !== null;
}
isAdmin() {
return localStorage.getItem('role') === 'admin';
}
}
Thanks.
You can achieve it by below way.
{path: 'login', component: LoginComponent}, // <--- This redirects to '/' in case user is logged in
{
path: '',
component: HomeComponent,
canActivate: [AuthGuardService],
}
this is your home component html(home.component.html)
<app-admin *ngIf="user_role==='admin'"></app-admin>
<app-user *ngIf="user_role==='user'"></app-user>
make sure you are assigning user_role in your typescript file of home component
this is your admin component html(admin.component.html)
<div>
this is admin component
</div>
this is your user component html(user.component.html)
<div>
this is user component
</div>
Hope, This will help you.
The problem is that you can't have two routes with the same path. The easiest change you can make is to change the path to something like this:
{
path: 'admin',
component: AdminComponent
},
{
path: 'user',
component: UserComponent
}
This is probably the best option because since you want your components to be different based on the user role. You might also want other components to be different and you can do that easily by adding children to the admin or the user routes.
In your AuthGuard you still only return true, but you make two other guards for the admin and user routes. Which check if the user is or isn't the admin.
And you redirect to the correct route by checking the user role once he loges in and then in the component you do router.navigate(['/admin']) or router.navigate(['/user'])
I'm new to angular 2 and trying to create a login app which I managed okay however after checking user/pass then redirect to dashboard it reloads the app. Is there a way to not refresh the page using router.navigate?
Edit: it redirects to dashboard first then reloads the page then redirects again back to dashboard.
import { Component } from '#angular/core';
import { Router, ROUTER_DIRECTIVES } from '#angular/router';
#Component({
selector: 'login',
templateUrl: './app/login/views/login.html',
})
export class LoginComponent {
constructor(public router: Router) {}
data = {
username: "",
password: "",
};
loginAction (){
if(this.data.username=="user1" && this.data.password=="pass1"){
console.log('do redirect to dashboard');
this.router.navigate(['dashboard']);
} else {
console.log('Something is wrong with your user/password.');
}
}
}
this.router.navigate(['/dashboard']);
Did you try relativeTo
router.navigate(['dashboard'], {relativeTo: route});
I'm trying to create an application with hash location strategy, but it does not add the hash to the url. For instance when I click on a button associated with { path: '/polls', name: 'Polls', component: PollsComponent } it loads the page with this url : localhost:3000/polls.
What do I have to change to get the hash location strategy?
Why do I have to set the default base url if I want to use hash location strategy?
This is the routing in the app.component.ts where all the routing is defined:
import {Component} from 'angular2/core'
import {HTTP_PROVIDERS, Http} from 'angular2/http';
import 'rxjs/Rx'; // load the full rxjs
import {ROUTER_PROVIDERS, RouteConfig , ROUTER_DIRECTIVES} from 'angular2/router';
import { ResultsComponent } from './results/results.component'
import { VotingCardsComponent } from './votingcards/votingcards.component'
import { DashBoardComponent } from './dash/dash.component'
import { PollsComponent } from './pollslist/pollslist.component'
#Component({
selector: 'my-app',
templateUrl: 'app/app.component.html',
directives: [ROUTER_DIRECTIVES, ResultsComponent, VotingCardsComponent, DashBoardComponent],
providers: [HTTP_PROVIDERS,
ROUTER_PROVIDERS]
})
#RouteConfig([
{ path: '/vote', name: 'VotePage', component: VotingCardsComponent },
{ path: '/votepoll/:id', name: 'VotePoll', component: VotingCardsComponent },
{ path: '/results', name: 'Results', component: ResultsComponent },
{ path: '/polls', name: 'Polls', component: PollsComponent },
{ path: '/', name: 'DashBoard', component: DashBoardComponent, useAsDefault: true }
])
export class AppComponent { }
And this is my main.ts where I configure the base url:
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from './app.component';
//this is to avoid the href empty issue
import {provide} from 'angular2/core';
import {APP_BASE_HREF, ROUTER_PROVIDERS} from 'angular2/router';
bootstrap(AppComponent, [
//this is to avoid the href empty issue
ROUTER_PROVIDERS,
provide(LocationStrategy, { useClass: HashLocationStrategy }),
provide(APP_BASE_HREF, { useValue: '/' })
]);
You can use the option "useHash" in RouterModule.forRoot().
RouterModule.forRoot(appRoutes, {useHash: true});
https://discuss.atom.io/t/angular-2-routes-breaking-on-electron-app-refresh/28370/4
ROUTER_PROVIDERS should not be added to child components,
only to
providers: [ROUTER_PROVIDERS]
or alternatively only to
bootstrap(AppComponent, [ROUTER_PROVIDERS]);
HTTP_PROVIDERS are in my opinion also a better fit for root component or bootstrap() but it doesn't break anything to add them somewhere else.
(See also Routing error with angular 2 and IIS)
Everything worked fine with the sample code OP posted as with what is in the accepted answer. But as a minor note, the format required to changing the Hash Location Strategy in the bootstrap file as of RC.4 goes like this:
{ provide: LocationStrategy, useClass: HashLocationStrategy },
It is recommended to use the HTML 5 style (PathLocationStrategy) as location strategy in Angular
Because
It produces the clean and SEO Friendly URLs that are easier for users
to understand and remember.
You can take advantage of the server-side rendering, which will make
our application load faster, by rendering the pages in the server
first before delivering it the client.
Use Hashlocationstrtegy only if you have to support the older
browsers.
Click Here for More info