route navigation is not working in angular 9 - javascript

I am working on a login and home component in my angular app.
Login service is validating the username and password of the user.
After successful login, it should redirect user to the home page.
But router redirect is not working properly.
login component
import { Router } from '#angular/router';
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { User } from 'src/app/shared/models/user';
import { AuthService } from '../services/auth.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html'
})
export class LoginComponent implements OnInit {
userName: FormControl;
password: FormControl;
loginFormGroup: FormGroup;
loginError: boolean;
errorMessage: string;
messageString: string;
constructor(private router: Router, private authService: AuthService) { }
ngOnInit() {
this.userName = new FormControl("", [Validators.required]);
this.password = new FormControl("", [Validators.required]);
this.loginFormGroup = new FormGroup({
userName: this.userName,
password: this.password
});
}
login() {
this.loginError = false;
if (this.loginFormGroup.valid) {
let user: User = new User();
user.userId = this.userName.value;
user.password = this.password.value;
this.authService.login(user)
.subscribe(res =>
{
console.log(res)
this.router.navigate(["home"])
console.log("res")
},
error =>
{
console.log(error)
});
}
}
}
and login service
import { Injectable } from "#angular/core";
import { Router } from "#angular/router";
import { Observable } from "rxjs";
import { share } from "rxjs/operators";
import { environment} from 'src/environments/environment';
import { HttpClient, HttpParams, HttpHeaders} from "#angular/common/http";
import { User } from 'src/app/shared/models/user';
#Injectable({ providedIn: "root" })
export class AuthService {
user: User;
resp=401;
get userDetail(): User {
return this.user;
}
constructor(
private router: Router,
private http: HttpClient
) {
}
login(user: User): Observable<any> {
var formData = new FormData();
formData.append("userId", user.userId);
formData.append("password", user.password);
return this.http.get<any>(url+"Validate_Login_User",{
headers: new HttpHeaders(),
params: new HttpParams().set("User_Id","user.userId")
})
}
}
routes
import { NgModule } from "#angular/core";
import { Routes, RouterModule } from "#angular/router";
import { AuthGuard } from "./authentication/services/auth.guard";
import { LoginComponent } from "./authentication/login/login.component";
import { LayoutComponent } from "./shared/components/layout/layout.component";
import { PageNotFoundComponent } from "./shared/components/page.not.found.component";
import { MenuComponent } from './menu/menu.component';
const routes: Routes = [
{ path: "login", component: LoginComponent },
{
path: "home",
component: HomeComponent,
canActivate: [AuthGuard],
children: [
{
//childroutes
},
{
//childroutes
},
],
},
{ path: "**", component: PageNotFoundComponent },
{ path: "Menu", component: MenuComponent}
];
#NgModule({
imports: [
RouterModule.forRoot(routes, {
onSameUrlNavigation: "ignore",
useHash: true,
}),
],
exports: [RouterModule],
})
export class AppRoutingModule {}
console log in login component
even though the console is printing success, route navigate is not happening and its still in login page

replace your code with the following piece of code, that should work.
this.loginError = false;
if (this.loginFormGroup.valid) {
let user: User = new User();
user.userId = this.userName.value;
user.password = this.password.value;
this.authService.login(user)
.subscribe(res =>
{
console.log(res)
this.router.navigate(["/home"])
console.log("res")
},
error =>
{
console.log(error)
});
}
}
Edited:
Please replace your ngModule with the below code:
#NgModule({
imports: [
RouterModule.forRoot(routes, {
useHash: true,
}),
],
exports: [RouterModule],
})

Try this.
this.router.navigateByUrl('/home');

Related

TypeError: Cannot read properties of undefined (reading 'subscribe') got error when try to run unit test

I have created a test case for my component with all dependency but when I execute the test case it shows error.
My unit test scenario is when form data is submitted formSubmit() method will be called and it send the data authservice there it makes an HTTP request and return some response. After that it navigate to another page.
Can anyone provide a solution for this test case??
Here are my code
login.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
// Services
import { ActivatedRoute, Router } from '#angular/router';
import { AuthService } from 'src/app/Service/auth.service';
// Material Component
import { MatSnackBar } from '#angular/material/snack-bar';
import { Title } from '#angular/platform-browser';
import { HttpErrorResponse } from '#angular/common/http';
import { LoginResponse } from '../../Model/auth';
import { duration, Notify } from '../../Model/notify';
import { NotificationComponent } from '../../shared/notification/notification.component';
import { NotifyService } from '../../Service/notify.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
})
export class LoginComponent implements OnInit {
constructor(
private documentTitle: Title,
private fb: FormBuilder,
private router: Router,
private route: ActivatedRoute,
private auth: AuthService,
private notify: NotifyService
) {}
passwordHide!: boolean;
returnUrl!: string;
pageTitle!: string;
loginForm!: FormGroup;
res!: LoginResponse;
ngOnInit(): void {
this.passwordHide = true;
this.pageTitle = 'Login | Online Shopping for Men & Women Shoes';
this.documentTitle.setTitle(this.pageTitle);
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '';
this.loginForm = this.fb.group({
username: ['', [Validators.required, Validators.minLength(8)]],
password: ['', [Validators.required, Validators.minLength(6)]],
});
}
/**
* send a request to auth service to make HTTP POST request
* if form is valid
*/
formSubmit() {
if (this.loginForm.valid) {
console.log(this.returnUrl);
this.auth.login(this.loginForm.value).subscribe({
next: (data: LoginResponse) => {
console.log(data);
this.res = data;
localStorage.setItem('access_token', data.accessToken);
this.auth.authStatusToggle(true);
this.router.navigateByUrl(this.returnUrl);
},
error: (error: HttpErrorResponse) => {
console.log(error);
if (error.status == 400) {
this.notify.warning(error.error.message);
} else {
this.notify.warning(error.error.message);
}
},
});
}
}
}
login.component.spec.ts
import { CommonModule } from '#angular/common';
import { ComponentFixture, TestBed, getTestBed } from '#angular/core/testing';
import {
FormBuilder,
FormsModule,
ReactiveFormsModule,
Validators,
} from '#angular/forms';
import { AppModule } from 'src/app/app.module';
import { AuthService } from 'src/app/Service/auth.service';
import { LoginComponent } from './login.component';
import * as Rx from 'rxjs';
import { Title } from '#angular/platform-browser';
import { HttpClientModule } from '#angular/common/http';
import {
HttpClientTestingModule,
HttpTestingController,
} from '#angular/common/http/testing';
import { LoginResponse } from 'src/app/Model/auth';
import { ActivatedRoute, Router } from '#angular/router';
import { RouterTestingModule } from '#angular/router/testing';
import { NotifyService } from 'src/app/Service/notify.service';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let authService = jasmine.createSpyObj('AuthService', ['login']);
let mockRouter = jasmine.createSpyObj('Router', ['navigate']);
let route: ActivatedRoute;
let documentTitle: Title;
let injector: TestBed;
let fb = new FormBuilder();
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [LoginComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
AppModule,
HttpClientModule,
HttpClientTestingModule,
RouterTestingModule,
],
providers: [
{ provide: FormBuilder, useValue: fb },
{ provide: AuthService, useValue: authService },
{ provide: Router, useValue: mockRouter },
{
provide: ActivatedRoute,
useValue: {
snapshot: {
queryParams: {
returnUrl: '',
},
},
},
},
NotifyService,
Title,
],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
fixture.detectChanges();
component = fixture.componentInstance;
injector = getTestBed();
route = TestBed.get(ActivatedRoute);
documentTitle = injector.get(Title);
fb = TestBed.inject(FormBuilder);
component.passwordHide = true;
component.pageTitle = 'Login | Online Shopping for Men & Women Shoes';
documentTitle.setTitle(component.pageTitle);
component.returnUrl = route.snapshot.queryParams['returnUrl'] || '';
component.loginForm = fb.group({
username: ['', [Validators.required, Validators.minLength(8)]],
password: ['', [Validators.required, Validators.minLength(6)]],
});
});
it('should form submit successfully', () => {
// console.log(route.snapshot.queryParamMap.get('returnUrl'))
// console.log(component.returnUrl);
component.loginForm.get('username')?.setValue('ramkumar');
component.loginForm.get('password')?.setValue('Ramkumar#45');
expect(component.loginForm.valid).toBeTruthy();
authService.login.and.returnValue(
Rx.of({
accessToken: 'testToken',
username: 'test',
userId: 1,
} as LoginResponse)
);
component.formSubmit();
expect(component.res).toEqual({
accessToken: 'testToken',
username: 'test',
userId: 1,
} as LoginResponse);
expect(mockRouter.navigate).toHaveBeenCalledWith(['']);
});
});
auth.service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Router } from '#angular/router';
import { Observable, Subject } from 'rxjs';
import { environment } from 'src/environments/environment';
import { Login, LoginResponse, Register } from '../Model/auth';
import { JwtHelperService } from '#auth0/angular-jwt';
import { UserResponse } from '../Model/user';
#Injectable({
providedIn: 'root',
})
export class AuthService {
private AUTH_API: string = environment.AUTH_API;
private USER_API: string = environment.USER_API;
public isUserLoggedIn: boolean = this.getAuthStatus();
private isLoggedIn: Subject<boolean> = new Subject<boolean>();
private token: any = localStorage.getItem('access_token')?.toString() || null;
private jwt: JwtHelperService;
/**
* Dependency Injections
* #param http
* #param route
*/
constructor(private http: HttpClient, private route: Router) {
this.jwt = new JwtHelperService();
this.isLoggedIn.subscribe((value) => {
console.log(value);
this.isUserLoggedIn = value;
});
}
/**
* Send user credentials to Auth API for create JWT token
* #param data
*/
login(data: Login): Observable<LoginResponse> {
return this.http.post<LoginResponse>(`${this.AUTH_API}/CreateToken`, data);
}
/**
* Send HTTP request to register new user
* #param data
*/
register(data: Register): Observable<UserResponse> {
return this.http.post<UserResponse>(`${this.USER_API}`, data);
}
/**
* Remove JWT token from localstorage to logout
*/
logout(): void {
localStorage.removeItem('access_token');
this.authStatusToggle(false);
if (this.getUserToken() == null) this.route.navigate(['login']);
}
/**
* get user JWT token from localstorage
* return token as string or null
*/
getUserToken(): string {
if (localStorage.getItem('access_token') != null) {
this.token = localStorage.getItem('access_token')?.toString() || null;
} else {
this.token = null;
}
return this.token;
}
authStatusToggle(value: boolean) {
this.isLoggedIn.next(value);
}
getAuthStatus(): boolean {
let token = localStorage.getItem('access_token')?.toString();
console.log(token);
if (token == null) {
return false;
}
return true;
}
}

Expected spy navigate to have been called

I have created a route after user logged-in in my angular app (Angular 8). now am trying to write a test case. But its giving below error.
route (/profile) page was not able to call.
Expected spy navigate to have been called with:
[ [ '/profile' ] ]
but it was never called.
login.component.js
import { Component, OnInit } from '#angular/core';
import { UserService } from '../../services/user.service';
import { User } from '../../models/user';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
user: User = new User();
errorMessage: string;
constructor(private userService: UserService, private router: Router){ }
ngOnInit(): void {
if(this.userService.currentUserValue){
this.router.navigate(['/home']);
return;
}
}
login() {
this.userService.login(this.user).subscribe(data => {
this.router.navigate(['/profile']);
}, err => {
this.errorMessage = "Username or password is incorrect.";
});
}
}
login.component.spec.ts
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { LoginComponent } from './login.component';
import { UserService } from 'src/app/services/user.service';
import { Router } from '#angular/router';
import { FormsModule } from '#angular/forms';
import { ExpectedConditions } from 'protractor';
import { DebugElement } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { HomeComponent } from '../home/home.component';
import { ProfileComponent } from '../profile/profile.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let debugElement: DebugElement;
let location, router: Router;
let mockRouter;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule, FormsModule ],
declarations: [ LoginComponent, ProfileComponent ],
providers: [UserService]
})
.compileComponents();
}));
beforeEach(() => {
mockRouter = { navigate: jasmine.createSpy('navigate') };
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([
{ path: 'profile', component: ProfileComponent }
])],
declarations: [LoginComponent, ProfileComponent],
providers: [
{ provide: Router, useValue: mockRouter},
]
});
});
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement;
});
it('should go profile ', async(() => {
fixture.detectChanges();
component.login();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/profile']);
}));
});
Why are you configuringTestingModule twice?
You should mock userService.
Try:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '#angular/common/http/testing';
import { LoginComponent } from './login.component';
import { UserService } from 'src/app/services/user.service';
import { Router } from '#angular/router';
import { FormsModule } from '#angular/forms';
import { ExpectedConditions } from 'protractor';
import { DebugElement } from '#angular/core';
import { RouterTestingModule } from '#angular/router/testing';
import { HomeComponent } from '../home/home.component';
import { ProfileComponent } from '../profile/profile.component';
import { of } from 'rxjs'; // import of from rxjs
import { throwError } from 'rxjs'; // import throwError
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let debugElement: DebugElement;
let mockUserService = jasmine.createSpyObj('userService', ['login']);
mockUserService.currentUserValue = /* mock currentUserValue to what it should be */
let router: Router;
beforeEach(async(() => {
// I don't think you need HttpClientTestingModule or maybe FormsModule
TestBed.configureTestingModule({
imports: [ HttpClientTestingModule, FormsModule, RouterTestingModule.withRoutes([
{ path: 'profile', component: ProfileComponent }
])],
declarations: [LoginComponent, ProfileComponent],
providers: [{ provide: UserService, useValue: mockUserService }]
})
.compileComponents();
}));
beforeEach(() => {
router = TestBed.get(Router); // remove the let here !!!!
spyOn(router, 'navigate'); // spy on router navigate
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement;
});
it('should go profile ', async(() => {
fixture.detectChanges();
mockUserService.login.and.returnValue(of({})); // mock login method on userService when it is called
component.login();
expect(router.navigate).toHaveBeenCalledWith(['/profile']);
}));
it('should set error message on error ', async(() => {
fixture.detectChanges();
mockUserService.login.and.returnValue(throwError('Error')); // mock login method on userService when it is called
component.login();
expect(component.errorMessage).toBe('Username or password is incorrect.');
}));
});

Error: Can't resolve all parameters for LoginPage: ([object Object], [object Object], [object Object], ?)

I faced with next error and cannot understand how to resolve it.
Error: Can't resolve all parameters for LoginPage: ([object Object], [object Object], [object Object], ?).
I've checked almost every topic here and have tried multiple ways to resolve it but still can't beat it already second day.
Login.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams,AlertController } from 'ionic-angular';
import { AuthProvider } from '../../providers/auth/auth';
import { TabsPage } from '../tabs/tabs';
/**
* Generated class for the LoginPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class LoginPage {
email:string = '';
password:string = '';
errorMsg:string;
constructor(
public navParams: NavParams,
public navCtrl: NavController,
public alertCtrl: AlertController
public authService: AuthProvider,
) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad LoginPage');
}
errorFunc(message){
let alert = this.alertCtrl.create({
title: 'oops!',
subTitle: message,
buttons: ['OK']
});
alert.present();
}
myLogIn(){
if (this.email.trim() !=='' ) {
console.log(this.email.trim() + " " + this.password.trim() )
if (this.password.trim() === '') {
this.errorFunc('Please put your password')
}
else{
let credentials = {
email: this.email,
password: this.password
};
this.authService.login(credentials).then((result) => {
console.log(result);
this.navCtrl.setRoot(TabsPage);
}, (err) => {
console.log(err);
this. errorFunc('Wrong credentials ! try again')
console.log("credentials: "+JSON.stringify(credentials))
});
}
}
else{
this. errorFunc('Please put a vaild password ! for ex:(123456)')
}
}
myLogOut(){
this.authService.logout();
}
}
Auth.ts
import { Injectable } from '#angular/core';
import { Storage } from '#ionic/storage';
import { Http , Headers } from '#angular/http';
import { TabsPage } from '../../pages/tabs/tabs';
#Injectable()
export class AuthProvider {
rootPage:any = TabsPage;
public token:any;
constructor(public storage:Storage ,public http: Http) {
console.log('Hello AuthProvider Provider');
}
login(credentials){
return new Promise((resolve, reject) => {
let headers = new Headers();
headers.append('Access-Control-Allow-Origin' , '*');
headers.append('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT');
headers.append('Accept','application/json');
headers.append('Content-type','application/json');
headers.append('X-Requested-With','XMLHttpRequest');
this.http.post('http://127.0.0.1:8000/api/auth/login', JSON.stringify(credentials), {
headers: headers})
.subscribe(res => {
let data = res.json();
this.token = data.token;
localStorage.setItem('token',data.access_token);
resolve(data);
}, (err) => {
reject(err);
}); });
}
checkAuthentication(){
return new Promise((resolve, reject) => {
this.storage.get('token').then((value) => {
this.token = value;
resolve(this.token)
})
});
}
logout(){
localStorage.setItem('token','');
}
}
app.moodule.ts
import { NgModule, ErrorHandler } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { IonicStorageModule } from '#ionic/storage';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { LoginPage } from '../pages/login/login';
import { AddPage } from '../pages/add/add';
import { AuthProvider } from '../providers/auth/auth';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { HttpModule } from '#angular/http';
import { ComplaintProvider } from '../providers/complaint/complaint';
#NgModule({
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
LoginPage,
AddPage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
IonicStorageModule.forRoot(),
HttpModule
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
LoginPage,
AddPage
],
providers: [
StatusBar,
SplashScreen,
AuthProvider,
ComplaintProvider,
{provide: ErrorHandler, useClass: IonicErrorHandler},
]
})
export class AppModule {}
You seem to be having a classic circular reference going around. You have the "TabsPage" imported in both Auth.ts & in your "LoginPage.ts".
A Classic Circular Reference.
Try removing the TabsPage from Auth.ts. In general, it is best if you have your components do very specific things so that you have a granular code and avoid such circular reference issues.

Angular routing including auth guard and redirections

I have an angular app and want to implement client side routing. I have 3 components: login, chat and admin. Access to admin and chat is restricted by an auth guard. Ideally the routing behavior should be:
click login -> route to login and redirect to admin
click admin or chat -> route to login and redirect on successful login to the clicked on (admin or chat respectlively)
I managed to setup the redirections nearly correct, but the redirection when clicking login still depends on where I clicked before/last. Meaning that if the user clicks on login it will goto login and on successful login it redirects to chat. The user then logs out and clicks login, it goes to login but redirects to chat instead of admin, which I don't want. Clicks on login should always go to admin regardless of which route was active in past.
How can I achieve this?
Thanks.
app.component
<nav>
<ol>
<li><a routerLink="/login">Login</a></li>
<li><a routerLink="/admin">Admin</a></li>
<li><a routerLink="/chat">Chat</a></li>
</ol>
</nav>
<router-outlet></router-outlet>
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
}
Login component
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { HttpClient } from '#angular/common/http';
import {AuthService} from "../auth.service";
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
email: string;
password: string;
loginMessage: string;
loginForm: FormGroup;
constructor(
private http: HttpClient,
) { }
ngOnInit() {
this.loginForm = new FormGroup({
'email': new FormControl(this.email, [
Validators.required,
Validators.email
]),
'password': new FormControl(this.password, [
Validators.required,
Validators.minLength(2)
])
});
console.log('init');
}
logout(): void {
this.authService.loggedIn = false;
}
login(): void {
if (!this.isValidInput()) { return; }
const data = {email: this.email, pass: this.password};
this.authService.login('localhost:3000/login', data).subscribe((response: any) => {
this.loginForm.reset();
this.authService.loggedIn=true;
let redirect = this.authService.redirecturl ? this.router.parseUrl(this.authService.redirecturl) : '/admin';
this.router.navigateByUrl(redirect);
});
}
isValidInput(): Boolean {
if (this.loginForm.valid) {
this.email = this.loginForm.get('email').value;
this.password = this.loginForm.get('password').value;
return true;
}
return false;
}
}
<form [formGroup]="loginForm">
<!-- this div is just for debugging purpose -->
<div id="displayFormValues">
Value: {{loginForm.value | json}}
</div>
<label for="email"><b>Email</b></label>
<input id="email" type="email" formControlName="email" email="true" required>
<label for="password"><b>Password</b></label>
<input id="password" type="password" formControlName="password" required>
<button (click)="login()" routerLink="/admin" routerLinkActive="active">Login</button>
<div id="loginMessage">{{loginMessage}}</div>
</form>
admin component
<p>admin works!</p>
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.css']
})
export class AdminComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
chat component
<p>chat works!</p>
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.css']
})
export class ChatComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
authgauard
import { Injectable } from '#angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor() {
}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url: string = state.url;
if (this.authService.isLoggedIn()) {
return true;
} else {
this.authService.redirecturl = url;
this.router.navigate(['/login']);
return false;
}
}
}
app-routing module
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { ChatComponent } from './chat/chat.component';
import { AdminComponent } from './admin/admin.component';
import { LoginComponent } from './login/login.component';
import { AuthGuard } from './auth.guard';
const routes: Routes = [
{
path: 'login',
component: LoginComponent
},
{
path: 'admin',
component: AdminComponent,
canActivate: [AuthGuard]
},
{
path: 'chat',
component: ChatComponent,
canActivate: [AuthGuard]
}
];
#NgModule({
imports: [RouterModule.forRoot(routes, {enableTracing: true})],
exports: [RouterModule]
})
export class AppRoutingModule { }
auth service
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { throwError, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
#Injectable({
providedIn: 'root'
})
export class AuthService {
redirecturl: string; // used for redirect after successful login
username: string;
loginMessage: string;
greeting = 'Hello guest!';
loggedIn = false;
config = {
serverHost: 'localhost',
serverPort: 3000,
loginRoute: 'login',
standardGreeting: `Hello guest!`,
standardUsername: 'Guest'
};
constructor(private http: HttpClient) { }
login(loginUrl: any, body: { pass: string }) {
return this.http.post(loginUrl, body, httpOptions)
.pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
console.error('An error occurred:', error.error.message);
} else {
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
return throwError(
'Something bad happened; please try again later.');
}
isLoggedIn(): boolean {
return this.loggedIn;
}
}
}
Instead of doing this <button (click)="login()" routerLink="/admin" routerLinkActive="active">Login</button> in html put redirection url in typescript like this.
login(): void {
if (!this.isValidInput()) { return; }
const data = {email: this.email, pass: this.password};
this.authService.login('localhost:3000/login', data).subscribe((response: any) => {
if(response.isSuccess){
this.loginForm.reset();
this.authService.loggedIn=true;
if(!this.authService.redirectUrl){
this.router.navigateByUrl('/admin');
} else{
this.router.navigateByUrl(this.authService.redirectUrl);
}
}
});
}
and If you are navigating to Login URL then please remove redirectUrl other wise it will always redirect to last visited page.
EDIT
In App.component.html you are navigating to login using routerlink instead of that use this
<nav>
<ol>
<li><a (click)='redirectToLogin()'>Login</a></li>
<li><a routerLink="/admin">Admin</a></li>
<li><a routerLink="/chat">Chat</a></li>
</ol>
</nav>
<router-outlet></router-outlet>
and in app.component.ts use this
redirectToLogin(){
this.authService.redirectUrl = null;
this.router.navigateByUrl('/login');
}

Angular 6 + Routes Resolver = 404 page in production

I am new to Angular Community coming from rails ; I am working on a site where I can post case studies of my clients website. So far I am loving angular but I am running into an issue that worries me a bit. The issue that I cant seem to use hyperlinks to reference any of the projects. For example if you click on this the application will return a 404 status but if you start from the root page everything will run no problem.
Solutions I have tried
Adding a resolver to the route to fetch the data before loading the
page; it works but still no hyperlink.
Can anyone help me figure out what I am missing or doing wrong;
Below is my code; Any help would be appreciated
Project.service.ts
import { AngularFirestore } from 'angularfire2/firestore';
import { Observable, of } from 'rxjs';
import { map, } from 'rxjs/operators';
import { Injectable } from '#angular/core';
import { Project } from '../../models/project';
import { HttpClient } from '#angular/common/http';
import { Post } from '../post';
#Injectable()
export class ProjectService {
ProjectListRef: Observable<any[]>;
featuredProjectList: Observable<any[]>;
posts: Array<Post>;
constructor( private database: AngularFirestore, private http: HttpClient) {
// Link For All Projects Page
const allProjectsListLink = this.database.collection<Project>('projects', ref => ref.orderBy('company_name'));
// Link For Featured Project Page
const featuredProjectsListLink = this.database.collection<Project>('projects', ref => ref.limit(5));
this.ProjectListRef = allProjectsListLink.snapshotChanges()
// using map pipe
.pipe(map( actions => {
return actions.map(a => {
// Get Document Data
const data = a.payload.doc.data() as Project;
// Get Document Id
const id = a.payload.doc.id;
return {id, ...data};
});
}));
this.featuredProjectList = featuredProjectsListLink.snapshotChanges()
// using map pipe
.pipe(map( actions => {
return actions.map(a => {
// Get Document Data
const data = a.payload.doc.data() as Project;
// Get Document Id
const id = a.payload.doc.id;
return {id, ...data};
});
}));
}
getAllProjects() {
return this.ProjectListRef;
}
getFeaturedProjects() {
return this.featuredProjectList;
}
getProject(id: string) {
console.log(id);
return this.database.collection('projects').doc(id)
.ref.get().then( doc => doc.data() );
}
}
Project.component.ts
import { Component, OnInit, Injectable, Inject } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { tap } from 'rxjs/operators';
import { ProjectService } from '../../app/services/project.service';
import { AngularFirestore } from 'angularfire2/firestore';
import { Project } from '../../models/project';
import { DOCUMENT } from '#angular/common';
#Injectable()
#Component({
selector: 'app-project-page',
templateUrl: './project-page.component.html',
styleUrls: ['./project-page.component.scss']
})
export class ProjectPageComponent implements OnInit {
project: Project;
projectId: any;
projectRef: any;
constructor(#Inject(DOCUMENT) private document: any, private router: Router,
private route: ActivatedRoute,
public database: AngularFirestore,
private projectService: ProjectService
) {
}
ngOnInit() {
// print out the data from the route resolver
this.route.data.pipe(
tap(console.log))
.subscribe(
data => this.project = data['project']
);
}
goToWebsite(url) {
this.document.location.href = url;
}
}
3. **ProjectResolver.ts**
import { ProjectService } from './../../app/services/project.service';
import { Project } from './../project';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { Observable } from 'rxjs';
import { Injectable } from '#angular/core';
#Injectable()
export class ProjectResolver implements Resolve<Project> {
constructor(private projectService: ProjectService) {
}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<Project>|Promise<any> {
return this.projectService.getProject(route.params['id']);
}
}
Application Routes
import { AddLeadPageComponent } from './add-lead-page/add-lead-page.component';
import { GoogleAdsPageComponent } from './google-ads-page/google-ads-page.component';
import { WebAppsPageComponent } from './web-apps-page/web-apps-page.component';
import { BrandedWebsitesPageComponent } from './branded-websites-page/branded-websites-page.component';
import { ServiceOverviewPageComponent } from './service-overview-page/service-overview-page.component';
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { HomePageComponent } from './home-page/home-page.component';
import { AboutPageComponent } from './about-page/about-page.component';
import { BlogPageComponent } from './blog-page/blog-page.component';
import { WebServicesPageComponent } from './web-services-page/web-services-page.component';
import { SEMPageComponent } from './sempage/sempage.component';
import { ContactPageComponent } from './contact-page/contact-page.component';
import { AllProjectsPageComponent } from './all-projects-page/all-projects-page.component';
import { ResearchServicePageComponent } from './research-service-page/research-service-page.component';
import { ProjectPageComponent } from './project-page/project-page.component';
import { TeamPageComponent } from './team-page/team-page.component';
import { NewProjectComponent } from './new-project/new-project.component';
import { DigitalMarketingPageComponent } from './digital-marketing-page/digital-marketing-page.component';
import { ProjectResolver } from '../models/resolvers/project.resolver';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomePageComponent},
{ path: 'about', component: AboutPageComponent},
{ path: 'blog', component: BlogPageComponent},
{ path: 'team', component: TeamPageComponent},
{ path: 'portfolio', component: AllProjectsPageComponent},
{ path: 'services', component: ServiceOverviewPageComponent},
{ path: 'project/:id', component: ProjectPageComponent, resolve: { project: ProjectResolver}},
{ path: 'brand-strategy', component: ResearchServicePageComponent},
{ path: 'digital-strategy', component: DigitalMarketingPageComponent},
{ path: 'custom-websites', component: BrandedWebsitesPageComponent},
{ path: 'web-apps', component: WebAppsPageComponent},
{ path: 'google-ads', component: GoogleAdsPageComponent},
{ path: 'web-design-development', component: WebServicesPageComponent},
{ path: 'search-engine-marketing', component: SEMPageComponent},
{ path: 'start-new-project', component: ContactPageComponent},
{ path: 'new-project', component: NewProjectComponent},
// post trial
{ path: 'posts/add', component: AddLeadPageComponent},
{ path: 'posts/add/:id', component: AddLeadPageComponent},
];
#NgModule({
imports: [
RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled'})
],
exports: [RouterModule]
})
export class AppRoutingModule { }
You don't have any error in your angular code. The problem you are facing is that the urls are not being rewritten to index.html. You need to configure this in your Firebase settings(firebase.json). This is the easiest and most common configuration:
"hosting": {
"public": "dist",
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}

Categories

Resources