I have a simple login form component (LoginComponent
) that calls the submitLogin
method.
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { first } from 'rxjs/operators';
import { AuthenticationService } from '../../services';
@Component({
selector: 'login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
returnURL: string;
u = new FormControl('');
p = new FormControl('');
constructor(private route: ActivatedRoute, private router: Router, private auth: AuthenticationService) { }
ngOnInit() {
this.returnURL = this.route.snapshot.queryParams['returnUrl'] || '/';
}
submitLogin(): void {
this.auth.login(this.u.value, this.p.value).pipe(first()).subscribe(
r => {
if (r) {
console.log("LoginComponent: r:", r);
this.router.navigate([this.returnURL]);
}
},
error => {
console.error("LoginComponent: Error:", error);
}
);
}
}
The error I'm getting is getting printed as LoginComponent: Error: TypeError: 'values' is undefined
, and it's getting printed in that error lambda.
The AuthenticationService
looks (roughly) like this:
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { User } from '../models/user';
import { APIService } from './api.service';
@Injectable({ providedIn: 'root' })
export class AuthenticationService {
private currentUserSubject: BehaviorSubject<User>;
public currentUser: Observable<User>;
constructor(private http: HttpClient, private api: APIService) {
this.currentUserSubject = new BehaviorSubject<User>(null);
this.currentUser = this.currentUserSubject.asObservable();
}
login(u: string, p: string): Observable<boolean> {
return this.api.login(u, p).pipe(map(
r => {
if (r && r.status === 200) {
this.updateCurrentUser();
console.log("returning true");
return true;
}
console.log("returning false");
return false;
}
));
}
}
Notice that all code paths in the map lambda return a boolean value. So this map should never spit out undefined
values. Those console logs never happen, by the way.
And my API service is responsible for making calls to a versioned API I have running. It's got a lot of unrelated stuff in it, but the relevant bits are:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, first } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class APIService {
public API_VERSION = '1.5';
private cookies: string;
constructor(private http: HttpClient) {}
private do(method: string, path: string, data?: Object): Observable<HttpResponse<any>> {
const options = {headers: new HttpHeaders({'Content-Type': 'application/json',
'Cookie': this.cookies}),
observe: 'response' as 'response',
body: data};
return this.http.request(method, path, options).pipe(map(r => {
//TODO pass alerts to the alert service
let resp = r as HttpResponse<any>;
if ('Cookie' in resp.headers) {
this.cookies = resp.headers['Cookie']
}
console.log("returning resp");
return resp;
}));
}
public login(u, p): Observable<HttpResponse<any>> {
const path = '/api/'+this.API_VERSION+'/user/login';
return this.do('post', path, {u, p});
}
}
Note that again, every code path in the map lambda returns a value. Also note that "returning resp"
never appears in the console. I also never see an HTTP request being made in the network panel. What gives? Why isn't it doing the request, and/or what could possibly be causing this error?
The stacktrace I got in the console after replicating your code led me to the 'lazyInit' function within the headers code of Angular's httpClient module (node_modules\@angular\common\esm5\http\src\headers.js
).
In the second line of the function, it iterates over the values of the header you're submitting, and you can see the values
variable on the third. There it gets one of the headers and accesses it's values. Next it converts it to an array, if it's a string, and then checks it's length - at this point you get the exception.
If you look at your API service, there's two headers you're submitting:
'Content-Type': 'application/json',
'Cookie': this.cookies
And earlier, you define the cookies
variable like this:
private cookies: string;
Since you don't assign a value, it defaults to undefined
, which is then the value of your 'Cookie' header, which is not a string and also doesn't have a length
property, so it's throwing an Exception.
Solution:
Changing the initial definition of cookies
to
private cookies = '';
fixes this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With