Angular2 function in a service undefined - javascript

i try to call a service's function(loginFb in auth.service.ts) from a component (fb.component.ts).
It seems that i imported everything and init the service. but still getting a 'loginfb' undefined error.
my auth.service.ts:
import { Injectable } from '#angular/core';
import { Headers, Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class AuthService {
constructor(private http: Http) {}
loginFb(uid, accessToken): boolean{
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let body = JSON.stringify({"uid":uid,"accessToken": accessToken});
this.http.post('http://localhost:3002/signinfb',body,{headers:headers})
.toPromise()
.then(response => {
localStorage.setItem('id_token', response.json().id_token);
return true;
})
.catch(this.handleError);
return false;
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
in my fb.component.ts:
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
import { AuthService } from './auth.service';
declare const FB:any;
#Component({
selector: 'facebook-login',
providers: [AuthService],
template: `
<div>
<button class="btn" (click)="onFacebookLoginClick()">
Sign in with Facebook
</button>
</div>
`,
})
export class FacebookLoginComponent implements OnInit{
constructor(private authService: AuthService) {
}
ngOnInit() {
FB.init({
appId : '234244113643991',
cookie : false,
xfbml : true,
version : 'v2.7'
});
}
statusChangeCallback(response) {
if (response.status === 'connected') {
let uid = response.authResponse.userID;
let accessToken = response.authResponse.accessToken;
// window.alert(uid+"|"+accessToken);
if (this.authService.loginFb(uid,accessToken)){
window.alert("GOOD!");
}else{
}
}else if (response.status === 'not_authorized') {
}else {
}
}
onFacebookLoginClick() {
FB.login(this.statusChangeCallback,
{scope: 'public_profile,email,user_friends,'});
}
}
I am getting:
Subscriber.ts:241 Uncaught TypeError: Cannot read property 'loginFb' of undefined(…)
Can someone help me with this problem? thanks!

You need to bind this to the proper context with statusChangeCallback
FB.login(this.statusChangeCallback.bind(this),
or make statusChangeCallback an arrow function
statusChangeCallback = (response) => {

Related

next.handle(request) in multiple HTTP interceptors fails: undefined

In a project, I work with 2 HTTP interceptors: 1 to add a JWT token to each request, the other to intercept an incoming 401 error status.
I call a separate program to get all feedback for my app in this service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { environment } from '#environments/environment';
import { Feedback } from '#app/_models/feedback';
#Injectable({ providedIn: 'root' })
export class FeedbackService {
constructor(
private http: HttpClient
) {}
getAll() {
return this.http.get<Feedback[]>(`${environment.apiUrl}/feedback`);
}
getById(id: string) {
return this.http.get<Feedback>(`${environment.apiUrl}/feedback/${id}`);
}
delete(id: string) {
return this.http.delete(`${environment.apiUrl}/feedback/${id}`);
}
}
The JWT interceptor:
import { Injectable } from '#angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '#angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '#environments/environment';
import { AuthorizationService } from 'src/shared/authorization.service';
#Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private auth: AuthorizationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add auth header with jwt if user is logged in and request is to the api url
const authenticatedUser = this.auth.getAuthenticatedUser();
if (authenticatedUser == null) {
return;
}
authenticatedUser.getSession( (err, session) => {
if (err) {
console.log(err);
return;
}
const isApiUrl = request.url.startsWith(environment.apiUrl);
const token = session.getIdToken().getJwtToken();
const headers = new Headers();
headers.append('Authorization', token);
if (this.auth.isLoggedIn() && isApiUrl) {
request = request.clone({
setHeaders: {
Authorization: token,
}
});
}
return next.handle(request);
});
}
}
The Error interceptor:
import { Injectable } from '#angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { AccountService } from '#app/_services';
#Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private accountService: AccountService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log(next.handle(request));
return next.handle(request).pipe(catchError(err => {
if (err.status === 401) {
// auto logout if 401 response returned from api
this.accountService.logout();
}
const error = err.error.message || err.statusText;
return throwError(error);
}));
}
}
When I provide both interceptors in my app.module,
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
I always get an error saying the following below. This happens because next.handle(request) apparently is undefined, and I don't really know why. Using only the Error interceptor works with no issue.
ERROR TypeError: Cannot read property 'pipe' of undefined
at ErrorInterceptor.intercept (error.interceptor.ts:14)
at HttpInterceptorHandler.handle (http.js:1958)
at HttpXsrfInterceptor.intercept (http.js:2819)
at HttpInterceptorHandler.handle (http.js:1958)
at HttpInterceptingHandler.handle (http.js:2895)
at MergeMapSubscriber.project (http.js:1682)
at MergeMapSubscriber._tryNext (mergeMap.js:46)
at MergeMapSubscriber._next (mergeMap.js:36)
at MergeMapSubscriber.next (Subscriber.js:49)
at Observable._subscribe (subscribeToArray.js:3)
Using only the JwtInterceptor gives following error, which I can't figure out where it's coming from. Of course, I would want to use both. Am I missing something while configuring the multiple interceptors?
ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
at subscribeTo (subscribeTo.js:27)
at subscribeToResult (subscribeToResult.js:11)
at MergeMapSubscriber._innerSub (mergeMap.js:59)
at MergeMapSubscriber._tryNext (mergeMap.js:53)
at MergeMapSubscriber._next (mergeMap.js:36)
at MergeMapSubscriber.next (Subscriber.js:49)
at Observable._subscribe (subscribeToArray.js:3)
at Observable._trySubscribe (Observable.js:42)
at Observable.subscribe (Observable.js:28)
at MergeMapOperator.call (mergeMap.js:21)
Rewrite your JwtInterceptor:
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, from } from 'rxjs';
import { environment } from '#environments/environment';
import { AuthorizationService } from 'src/shared/authorization.service';
#Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private auth: AuthorizationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return from(this.getSessionWithAuthReq(request, next));
}
async getSessionWithAuthReq(request: HttpRequest<any>, next: HttpHandler){
const authenticatedUser = this.auth.getAuthenticatedUser();
if (authenticatedUser) {
const authRequest: HttpRequest<any> = await new Promise( (resolve) => {
authenticatedUser.getSession( (err, session) => {
if (err) {
console.log(err);
// want to go on without authenticating if there is an error from getting session
return resolve(request);
}
const isApiUrl = request.url.startsWith(environment.apiUrl);
const token = session.getIdToken().getJwtToken();
const headers = new Headers();
headers.append('Authorization', token);
if (this.auth.isLoggedIn() && isApiUrl) {
const req = request.clone({
setHeaders: {
Authorization: token,
}
});
return resolve(req);
}
return resolve(request);
});
});
return next.handle(authRequest).toPromise();
}
return next.handle(request).toPromise();
}
}

Angular 6 : Issue of component data binding

I call service which make http call, I assign response to component variable now when I try access that component variable to view it display blank.
Means component variable assign in subscribe successfully but cant acceess in html view.
I think view is loaded before values assign to component data.
component
import {Component, OnInit, ChangeDetectionStrategy} from '#angular/core';
import { UserService } from '../../../../../core/services/users/user.service';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'm-user-list',
templateUrl: './user-list.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserListComponent implements OnInit {
list;
roles = {};
current_page: any
totalRecords: any
public showContent: boolean = false;
constructor(private userService: UserService, private http: HttpClient) {
}
ngOnInit() {
this.getRecords();
}
getRecords(){
this.getResultedPage(1);
}
getResultedPage(page){
return this.userService.getrecords()
.subscribe(response => {
this.list = response.data;
});
}
}
Service
import { Injectable } from '#angular/core';
import { Observable, of, throwError } from 'rxjs';
import { HttpClient, HttpParams , HttpErrorResponse, HttpHeaders } from '#angular/common/http';
import { map, catchError, tap, switchMap } from 'rxjs/operators';
const httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json'})
};
import { UtilsService } from '../../services/utils.service';
import { AppConfig } from '../../../config/app'
#Injectable({
providedIn: 'root'
})
export class UserService{
public appConfig: AppConfig;
public API_URL;
constructor(private http: HttpClient, private util: UtilsService) {
this.appConfig = new AppConfig();
this.API_URL = this.appConfig.config.api_url;
}
private extractData(res: Response) {
let body = res;
return body || { };
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError('Something bad happened; please try again later.');
};
getrecords(): Observable<any> {
return this.http.get('/api/users', httpOptions).pipe(
map(this.extractData),
catchError(this.handleError));
}
}

Refresh token (JWT) in interceptor Angular 6

Initially, I had a function that simply checked for the presence of a token and, if it was not present, sent the user to the login header. Now I need to implement the logic of refreshing a token when it expires with the help of a refreshing token. But I get an error 401. The refresh function does not have time to work and the work in the interceptor goes further to the error. How can I fix the code so that I can wait for the refresh to finish, get a new token and not redirect to the login page?
TokenInterceptor
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from "#angular/common/http";
import {Injectable, Injector} from "#angular/core";
import {AuthService} from "../services/auth.service";
import {Observable, throwError} from "rxjs";
import {catchError, tap} from "rxjs/operators";
import {Router} from "#angular/router";
import {JwtHelperService} from "#auth0/angular-jwt";
#Injectable({
providedIn: 'root'
})
export class TokenInterceptor implements HttpInterceptor{
private auth: AuthService;
constructor(private injector: Injector, private router: Router) {}
jwtHelper: JwtHelperService = new JwtHelperService();
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.auth = this.injector.get(AuthService);
const accToken = this.auth.getToken();
const refToken = this.auth.getRefreshToken();
if ( accToken && refToken ) {
if ( this.jwtHelper.isTokenExpired(accToken) ) {
this.auth.refreshTokens().pipe(
tap(
() => {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${accToken}`
}
});
}
)
)
} else {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${accToken}`
}
});
}
}
return next.handle(req).pipe(
catchError(
(error: HttpErrorResponse) => this.handleAuthError(error)
)
);
}
private handleAuthError(error: HttpErrorResponse): Observable<any>{
if (error.status === 401) {
this.router.navigate(['/login'], {
queryParams: {
sessionFailed: true
}
});
}
return throwError(error);
}
}
AuthService
import {Injectable} from "#angular/core";
import {HttpClient, HttpHeaders} from "#angular/common/http";
import {Observable, of} from "rxjs";
import {RefreshTokens, Tokens, User} from "../interfaces";
import {map, tap} from "rxjs/operators";
#Injectable({
providedIn: 'root'
})
export class AuthService{
private authToken = null;
private refreshToken = null;
constructor(private http: HttpClient) {}
setToken(authToken: string) {
this.authToken = authToken;
}
setRefreshToken(refreshToken: string) {
this.refreshToken = refreshToken;
}
getToken(): string {
this.authToken = localStorage.getItem('auth-token');
return this.authToken;
};
getRefreshToken(): string {
this.refreshToken = localStorage.getItem('refresh-token');
return this.refreshToken;
};
isAuthenticated(): boolean {
return !!this.authToken;
}
isRefreshToken(): boolean {
return !!this.refreshToken;
}
refreshTokens(): Observable<any> {
const httpOptions = {
headers: new HttpHeaders({
'Authorization': 'Bearer ' + this.getRefreshToken()
})
};
return this.http.post<RefreshTokens>('/api2/auth/refresh', {}, httpOptions)
.pipe(
tap((tokens: RefreshTokens) => {
localStorage.setItem('auth-token', tokens.access_token);
localStorage.setItem('refresh-token', tokens.refresh_token);
this.setToken(tokens.access_token);
this.setRefreshToken(tokens.refresh_token);
console.log('Refresh token ok');
})
);
}
}
In your example you never subscribe to your refreshTokens().pipe() code. Without a subscription, the observable won't execute.
req = this.auth.refreshTokens().pipe(
switchMap(() => req.clone({
setHeaders: {
Authorization: `Bearer ${this.auth.getToken()}`
}
}))
)
This will first call refreshToken and run the tap there, then emit request with the new this.auth.getToken(), note that accToken still have old value as the code is not rerun.
You have to do something like that:
const firstReq = cloneAndAddHeaders(req);
return next.handle(firstReq).pipe(
catchError(
err => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401 || err.status === 403) {
if (firstReq.url === '/api2/auth/refresh') {
auth.setToken('');
auth.setRefreshToken('');
this.router.navigate(['/login']);
} else {
return this.auth.refreshTokens()
.pipe(mergeMap(() => next.handle(cloneAndAddHeaders(req))));
}
}
return throwError(err.message || 'Server error');
}
}
)
);
The implementation of cloneAndAddHeaders should be something like this:
private cloneAndAddHeaders(request: HttpRequest<any>): HttpRequest<any> {
return request.clone({
setHeaders: {
Authorization: `YourToken`
}
});
}

angular resolver does not have access to angular service properties

i have an anagular service called authservice ,which looks like this:
import { Injectable } from '#angular/core';
import { Http, Headers, RequestOptions, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { JwtHelperService} from '#auth0/angular-jwt';
#Injectable()
export class AuthService {
public DecdedToken: any;
userToken: any;
public userid: any;
helper: any = new JwtHelperService();
baseUrl = 'http://localhost:5000/api/auth/';
// userToken: any;
constructor(private http: Http , private jwthelpservicee: JwtHelperService) {}
login(model: any) {
return this.http.post(this.baseUrl + 'login', model, this.requestOptions()).map((response: Response) => {
const user = response.json();
if (user && user.stringToken) {
this.userToken = user.stringToken;
localStorage.setItem('token', user.stringToken);
this.DecdedToken = this.helper.decodeToken(user.stringToken);
this.userid = this.DecdedToken.nameid;
// console.log(this.userid);
// onsole.log('so far so good');
}
}).catch(this.HandleError);
}
register(model: any) {
return this.http.post(this.baseUrl + 'register', model, this.requestOptions()).catch(this.HandleError);
}
private requestOptions() {
const headers = new Headers({ 'Content-type': 'application/json' });
return new RequestOptions({ headers: headers });
}
IsLoggedIn() {
return !this.jwthelpservicee.isTokenExpired();
}
private HandleError(error: any) {
const applicationerror = error.headers.get('Application-Error');
if (applicationerror) {
return Observable.throw(applicationerror);
}
const serverError = error.json();
let modelStateErrors = '';
if (serverError) {
for (const key in serverError) {
if (serverError[key]) {
modelStateErrors += serverError[key] + '\n';
}
}
}
return Observable.throw(modelStateErrors || 'server error');
}
}
in login method DecodedToken gets its value.
i have a resolver too, in which i am trying to get a value of a property from authsercvice
import { Resolve, Router, ActivatedRouteSnapshot } from '../../../node_modules/#angular/router';
import { User } from '../_Models/user';
import { Injectable } from '../../../node_modules/#angular/core';
import { UserService } from '../_services/User.service';
import { AlertifyService } from '../_services/alertify.service';
import { Observable } from '../../../node_modules/rxjs';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/catch';
import { AuthService } from '../_services/auth.service';
#Injectable()
export class MemberEditResolver implements Resolve<User> {
constructor(private userservice: UserService ,
private router: Router ,
private alertify: AlertifyService,
private authservice: AuthService) {
}
resolve(route: ActivatedRouteSnapshot): Observable<User> {
console.log(this.authservice.userid);
return this.userservice.getuser(this.authservice.DecdedToken.nameid).catch(error => {
this.alertify.error('error');
this.router.navigate(['/members']);
return Observable.of(null);
});
}
}
as you can see i have defined DecdedToken as a public property, inside the authservice this property has value, but when i want to access it from resolver ,i get null or undefined...

Angular 5 component expecting an argument

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.

Categories

Resources