Why is my http.post not working in angular 2. Just can't figure out what I have been missing.
Here is login.component.ts file
export class LoginComponent implements OnInit{
model: any = {};
loading = false;
constructor(
private router: Router,
private authenticationService: AuthenticationService,
private alertService: AlertService
){}
ngOnInit(){
// reset login status
this.authenticationService.logout();
}
login(){
let errMsg: string;
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
console.log('Success');
//this.router.navigate(['/']);
},
error => {
console.log('Error');
this.loading = false;
}
);
}
Here is the authentication.service.ts
#Injectable()
export class AuthenticationService{
private baseUrl = '..';
constructor(private http: Http){}
login(username: string, password: string): Observable<Response>{
let body = JSON.stringify({username: username, password: password});
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers});
const url = `${this.baseUrl}/api/auth/login`;
return this.http.post(url, body, options)
.map(this.extractData)
.catch(this.handleError);
}
logout(){
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
}
private extractData(res: Response) {
let body = res.json();
return body.data || { };
}
private handleError (error: Response | any) {
// In a real world app, we might use a remote logging infrastructure
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
Here is the routes file
const appRoutes: Routes = [
{ path: '', component: LoginComponent },
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
// otherwise redirect to home
{ path: '**', redirectTo: '' }
];
#NgModule({
imports: [ RouterModule.forRoot(appRoutes) ],
exports: [ RouterModule ]
})
export class AppRoutingMoudle{}
Any help would be appreciated. Thank You!
import { Injectable } from '#angular/core';
import {Headers, Http, Response,RequestOptions} from '#angular/http';
import 'rxjs/add/operator/toPromise';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
import these above your services , then do it on constructor
constructor(private _http:Http) { }
then youcan use it with this._http.post
Related
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;
}
}
this is the authentication page:-
import {Injectable} from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {SECURITY} from '../constant/SecurityAPI';
import {CONFIG} from '../config';
#Injectable()
export class AuthenticationService {
constructor(private http: HttpClient) {
}
public isUserLoggedIn() {
return localStorage.getItem('token') === undefined;
}
public login(credentials) {
return new Promise((resolve, reject) => {
console.log('username ' , credentials.userName, ' pass ' , credentials.password );
const data = {userName: credentials.userName, password: credentials.password, orgId: CONFIG.ORG_ID};
this.http.post(SECURITY.GET_LOGIN_URL, JSON.stringify(data), {
headers: new HttpHeaders().set('Content-Type', 'application/json')
})
.subscribe(res => {
console.log('res ' , res);
resolve(res);
}, (err) => {
reject(err);
});
});
}
}
You need to specify in #Injectable decorator where you want to provide this service
#Injectable({
providedIn: 'root'
})
export class AuthenticationService {
...
}
or to add it in app.module.ts providers:
providers: [
AuthenticationService,
any other services,
...
]
I'm trying to Post data to rest API. I'm using Postman for my rest API.
Getting Cannot read property 'subscribe' of undefined on POST HTTP Call in console log:
My rest API: "dradiobeats.x10host.com/api/areas"
userService.ts:
import { Injectable, Input } from "#angular/core";
import { HttpClient, HttpHeaders } from "#angular/common/http";
import { userArray } from "./users.model";
import { Observable } from "rxjs";
const httpOptions = {
headers: new HttpHeaders({
"Content-Type": "application/json",
Authorization:
"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImYyOTc3OTBmODc3ODlhYzg3MGE2ZmU3YTY0YzY2YmIwOGU4M2Q0ZmQzY2IyNmNiNWU3NDEzMTFmZjExMDk4NTA5NWUzN2IxN2I5YmI2YmFjIn0.eyJhdWQiOiIyIiwianRpIjoiZjI5Nzc5MGY4Nzc4OWFjODcwYTZmZTdhNjRjNjZiYjA4ZTgzZDRmZDNjYjI2Y2I1ZTc0MTMxMWZmMTEwOTg1MDk1ZTM3YjE3YjliYjZiYWMiLCJpYXQiOjE1NzU4NzM4MzksIm5iZiI6MTU3NTg3MzgzOSwiZXhwIjoxNjA3NDk2MjM5LCJzdWIiOiIyIiwic2NvcGVzIjpbXX0.J3nMXcPpqlRVvIRkrVAMblSUwdlXFmrkn9SPD2WE1DwdiqAMdhay8zAeD550ta9qWiNxHOKMAWF8t3H9cIgItaB9ZX2CxoxzS5P1nJFzit8qxiB-gzJL3mpybrnLtrKGjxsM5i_lBvdJsnhWzi15jKWIu-RNxUYPnXCjuxnXYEiyoJg17hsYUh4910VfFWx4R3WvH7WOvczF53IDKyX5fSTt4WSJUqciuNepkO6Klc8sj_yPmDPQltUjUXSSplkOQ8sL5uHk7PmzSjIfoR8RC0A-YQqI9mbZMTyJ0IyKoAHvRHF8q1cW5qfUmLXTgxcCTmFPqXqIlcAoOoJMCxke5fl0PuK0rgU7dxouATk_3B6cio7-7Zgps0iopDpk2nm-o40mjSiOUGb2kyKckYN09orYuan5wEd1KJ873ejKEgBWOhJu4gQFps8M9VoDXncAqMxeBqbUY1UZENx_n6uduQ_SAY4rgIUFCixfNc5Y_-HLDa108u4-z3APGbdxrhEdZXyHz9xQTaLrWcU_iCJ5g_ObT5VGZHtawZbfOYm2ZZpjPiCZpXunhrsbAcHBX64akWcehmT2gUJqPsxvaObKN3nayML1NHtdZGgAHUE89clhIH610Fod0C_jMTqpU7IkY9aSU781HsQVlHNw3qGbTinWfYPDBG0Lkp9NnmRe9BU",
Accept: "application/json"
})
};
#Injectable({
providedIn: "root"
})
export class UsersService {
users$: userArray[];
apiUrl = "http://dradiobeats.x10host.com/api/areas";
delUrl = "http://dradiobeats.x10host.com/api/areas";
constructor(private _http: HttpClient) {}
getUsers() {
return this._http.get<userArray[]>(this.apiUrl);
}
deleteUser(id: userArray): Observable<userArray> {
const url = `${this.apiUrl}/${id}`;
console.log();
return this._http.delete<userArray>(url, httpOptions);
}
onSubmit(users$: userArray): Observable<userArray> {
console.log(users$);
this._http.post<userArray>(this.apiUrl, users$, httpOptions);
}
}
add-post.component.ts:
import { Component, OnInit } from "#angular/core";
import { UsersService } from "src/app/users.service";
import { userArray } from "src/app/users.model";
#Component({
selector: "app-add-posts",
templateUrl: "./add-posts.component.html",
styleUrls: ["./add-posts.component.css"]
})
export class AddPostsComponent implements OnInit {
name: string;
description: string;
domain: string;
picture: string;
id: number = 29;
constructor(private userService: UsersService) {}
users: userArray[];
ngOnInit() {}
onSubmit() {
const users$ = {
name: this.name,
description: this.description,
domain: this.domain,
picture: this.picture
};
this.userService.onSubmit(users$).subscribe();
}
}
Can someone please help?
You need to return the http call observable
Try:
onSubmit(users$: userArray): Observable<userArray> {
console.log(users$);
return this._http.post<userArray>(this.apiUrl, users$, httpOptions);
}
As onSubmit() has an Observable signature, it must return an observable. You must change your function to 'return this.http.post ...'
You forgot to return, As only observable can be subscribe
import { Injectable, Input } from "#angular/core";
import { HttpClient, HttpHeaders } from "#angular/common/http";
import { userArray } from "./users.model";
import { Observable } from "rxjs";
const httpOptions = {
headers: new HttpHeaders({
"Content-Type": "application/json",
Authorization:
"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImYyOTc3OTBmODc3ODlhYzg3MGE2ZmU3YTY0YzY2YmIwOGU4M2Q0ZmQzY2IyNmNiNWU3NDEzMTFmZjExMDk4NTA5NWUzN2IxN2I5YmI2YmFjIn0.eyJhdWQiOiIyIiwianRpIjoiZjI5Nzc5MGY4Nzc4OWFjODcwYTZmZTdhNjRjNjZiYjA4ZTgzZDRmZDNjYjI2Y2I1ZTc0MTMxMWZmMTEwOTg1MDk1ZTM3YjE3YjliYjZiYWMiLCJpYXQiOjE1NzU4NzM4MzksIm5iZiI6MTU3NTg3MzgzOSwiZXhwIjoxNjA3NDk2MjM5LCJzdWIiOiIyIiwic2NvcGVzIjpbXX0.J3nMXcPpqlRVvIRkrVAMblSUwdlXFmrkn9SPD2WE1DwdiqAMdhay8zAeD550ta9qWiNxHOKMAWF8t3H9cIgItaB9ZX2CxoxzS5P1nJFzit8qxiB-gzJL3mpybrnLtrKGjxsM5i_lBvdJsnhWzi15jKWIu-RNxUYPnXCjuxnXYEiyoJg17hsYUh4910VfFWx4R3WvH7WOvczF53IDKyX5fSTt4WSJUqciuNepkO6Klc8sj_yPmDPQltUjUXSSplkOQ8sL5uHk7PmzSjIfoR8RC0A-YQqI9mbZMTyJ0IyKoAHvRHF8q1cW5qfUmLXTgxcCTmFPqXqIlcAoOoJMCxke5fl0PuK0rgU7dxouATk_3B6cio7-7Zgps0iopDpk2nm-o40mjSiOUGb2kyKckYN09orYuan5wEd1KJ873ejKEgBWOhJu4gQFps8M9VoDXncAqMxeBqbUY1UZENx_n6uduQ_SAY4rgIUFCixfNc5Y_-HLDa108u4-z3APGbdxrhEdZXyHz9xQTaLrWcU_iCJ5g_ObT5VGZHtawZbfOYm2ZZpjPiCZpXunhrsbAcHBX64akWcehmT2gUJqPsxvaObKN3nayML1NHtdZGgAHUE89clhIH610Fod0C_jMTqpU7IkY9aSU781HsQVlHNw3qGbTinWfYPDBG0Lkp9NnmRe9BU",
Accept: "application/json"
})
};
#Injectable({
providedIn: "root"
})
export class UsersService {
users$: userArray[];
apiUrl = "http://dradiobeats.x10host.com/api/areas";
delUrl = "http://dradiobeats.x10host.com/api/areas";
constructor(private _http: HttpClient) {}
getUsers() {
return this._http.get<userArray[]>(this.apiUrl);
}
deleteUser(id: userArray): Observable<userArray> {
const url = `${this.apiUrl}/${id}`;
console.log();
return this._http.delete<userArray>(url, httpOptions);
}
onSubmit(users$: userArray): Observable<userArray> {
console.log(users$);
return this._http.post<userArray>(this.apiUrl, users$, httpOptions);
}
}
Im trying a simple profile app, and all the sudden Im getting error TS2554
ERROR in /app/components/profile/profile.component.ts(25,3): error TS2554: Expected 1 arguments, but got 0.
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { FlashMessagesService } from 'angular2-flash-messages';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(
private auth: AuthService,
private flashMsg: FlashMessagesService,
private router: Router
) {
}
ngOnInit() {
this.auth.getProfile().subscribe( profile => {
this.user = profile.user;
},
err => {
return false;
});
}
}
auth.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import { tokenNotExpired } from 'angular2-jwt';
#Injectable()
export class AuthService {
authToken: any;
user: any;
constructor(
private http: Http
) {
}
getProfile(user) {
let headers = new Headers();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type','application/json');
return this.http.get('http://localhost:3000/users/profile', {headers:headers})
.map(res => res.json());
}
loadToken() {
const token = localStorage.getItem('id_token');
this.authToken = token;
}
}
Your getProfile is expecting an argument named user but you are not passing it from the component
You need to pass an argument as follows,
this.auth.getProfile(user).subscribe( profile => {
this.user = profile.user;
},
err => {
return false;
});
or if you don't need an argument , remove it from your service method.
I have the following app.routes.ts
import {ModuleWithProviders} from '#angular/core';
import {Routes, RouterModule} from '#angular/router';
import { HomeComponent } from '../app/components/home/home.component';
import { LoginComponent } from '../app/components/login/login.component';
import { LoggedInGuard } from '../app/logged-in.guard';
import { CategoriesComponent} from '../app/components/categories/categories.component';
import { LogoutComponent } from '../app/components/logout/logout.component';
import { RegisterComponent} from '../app/components/register/register.component';
import { NotAuthorizedComponent} from '../app/components/not-authorized/not-authorized.component';
const appRoutes: Routes = [
{path: '', component: HomeComponent, pathMatch: 'full', canActivate: [LoggedInGuard]},
{path: 'login', component: LoginComponent},
{path: 'register', component: RegisterComponent},
{path: 'notAuthorized', component: NotAuthorizedComponent},
{path: 'categories', component: CategoriesComponent, canActivate: [LoggedInGuard]},
{path: 'logout', component: LogoutComponent, canActivate: [LoggedInGuard]},
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
and then I have a categories.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import {Observable} from 'rxjs/Observable';
import {Categories} from '../Categories';
import {Router} from '#angular/router';
#Injectable()
export class CategoriesService {
apiUrl: string;
categories: Categories[] = [];
constructor(private _http:Http, private router:Router) {
this.apiUrl = 'http://localhost:50424/api/';
}
getCategories() {
let headers = new Headers();
headers.append('Content-type', 'application/json');
let authToken = localStorage.getItem('auth_token');
headers.append('Authorization', `Bearer ${authToken}`);
return this._http.get(this.apiUrl+ 'Categories/Get', { headers: headers, withCredentials: true })
.map(this.extractObject)
.catch(this.handleError);
}
private extractObject(res: Response): Categories {
let categories = res.json();
return categories || { };
}
private handleError (error: any) {
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
if (error.status === 401 || error.status === 403) {
console.log('We have an unathorized request');
//handle authorization errors
this.router.navigate(['notAuthorized']);
}
return Observable.throw(errMsg);
}
}
which is basically getting some categories from an API. All works well, however I want to limit this for only authorized users. So when throwing a server error 401 or 403, I want to redirect the user to a NonAuthorized page. My code is getting to the
console.log('We have an unathorized request');
correctly, however it is not doing the redirection, and staying on the same page. What I can do to redirect the user to another "NonAuthorized" page?
Thanks for your help and time!
As discussed in the comments, the problem is a scope issue, since this.router is not known in the scope of the passed this.handleError. Therefore the signature needs to be changed to private handleError(error: any, router: Router) and the corresponding call in the subscription will be .catch(error => this.handleError(error, this.router))