19
votes

I am trying to get a list of Users from an API but I get the following error:

TypeError: Cannot read property 'toLowerCase' of undefined
at HttpXsrfInterceptor.intercept (http.js:2482)
at HttpInterceptorHandler.handle (http.js:1796)
at HttpInterceptingHandler.handle (http.js:2547)
at MergeMapSubscriber.eval [as project] (http.js:1466)
at MergeMapSubscriber._tryNext (mergeMap.js:128)
at MergeMapSubscriber._next (mergeMap.js:118)
at MergeMapSubscriber.Subscriber.next (Subscriber.js:92)
at ScalarObservable._subscribe (ScalarObservable.js:51)
at ScalarObservable.Observable._trySubscribe (Observable.js:172)
at ScalarObservable.Observable.subscribe (Observable.js:160)

I have a login component that calls the homeService.getUsers() which uses HttpClient to retrieve the users but the http request never reaches the server.

login.component.ts:

import { Component, OnInit } from '@angular/core';

import { HomeService } from '../service/home.service';
import { User } from '../domain/user';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {

  user: User = {
      id: undefined,
      userName: undefined,
      password: undefined
  }; 
  users: User[];

  constructor(
    private homeService: HomeService
  ) { }

  ngOnInit() {
    this.getUsers();
  }

  getUsers(): void {
    this.homeService.getUsers()
    .subscribe(users => this.users = users);
  }
}

Home.service:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';

import { User } from '../domain/user';
import { MessageService } from '../service/message.service';

const httpOptions = {
  headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

@Injectable()
export class HomeService {

  private usersUrl: 'http://localhost:8080/users';

  constructor(
    private http: HttpClient,
    private messageService: MessageService
  ) { }

  getUsers (): Observable<User[]> {
    return this.http.get<User[]>(this.usersUrl)
      .pipe(
        tap(users => this.log(`fetched users`)),
        catchError(this.handleError('getUsers', []))
      );
  }

  /**
  * Handle Http operation that failed.
  * Let the app continue.
  * @param operation - name of the operation that failed
  * @param result - optional value to return as the observable result
  */
  private handleError<T> (operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }

  private log(message: string) {
    this.messageService.add(message);
  }

}

and the app.module:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientXsrfModule } from '@angular/common/http';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { HomeService } from './service/home.service';
import { MessagesComponent } from './messages/messages.component';
import { MessageService } from './service/message.service';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    LoginComponent,
    RegisterComponent,
    MessagesComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule,
    HttpClientXsrfModule.withOptions({
      cookieName: 'My-Xsrf-Cookie',
      headerName: 'My-Xsrf-Header',
    })
  ],
  providers: [HomeService, MessageService],
  bootstrap: [AppComponent]
})
export class AppModule { }

I can see the error message displayed in the logging, so it seems like an error from the HttpClient. But I can't figure out why it is failing before sending the Http request to the server.

6
Bot cookieName: 'My-Xsrf-Cookie' and headerName: 'My-Xsrf-Header' are undefined, thats why!Fals
But if I remove the options of the import and leave the import as 'HttpClientXsrfModule' I keep getting the errorCanlla
Issue solved, usersUrl was badly assigned. Modified it to: private usersUrl: string = 'localhost:8080/users';Canlla
fwiw: I had this error and the fix was to wrap the url variable with tick marks in my service as such `${url}`Adam Mendoza

6 Answers

16
votes

I got the same issue. The problem was that I had declared the url, but when doing the httpget, i realized that the url was not assigned with any value:

Probable case: Example: private yourUrl: string;

and in your http call: return this.http.get(this.yourUrl, {headers : this.headers})

13
votes

it seems you have declared a variable wrongly thus making it undefined: Try this

For neat coding

interface User = {
      id: number;
      userName: string;
      password: string;
  }

user: User;

Also correct this line from

private usersUrl: 'http://localhost:8080/users';

To

private usersUrl =  'http://localhost:8080/users';

This is likely where the problem is

1
votes

i think your url declaration is not correct try the following way:

private usersUrl = 'http://localhost:8080/users';

1
votes

The issue is with the URL that you have passed: private usersUrl: http://localhost:8080/users'; .

It should be like: private usersUrl: string='http://localhost:8080/users';

0
votes

I had the same problem. As @Canlla said, it was necessary to change the visibility of the url variable from public to private.

Strange, but something was changing its value! Anyway, it must be private, since we don't need acess it on tamplate.

In my case, in addition, I needed to add NgIf / NgElse to avoid data binding before the load completes:

<mat-list *ngIf="transactions | async; let transactions;else loading">
      <div *ngFor="let transaction of transactions">
        <h3 mat-subheader>{{ transaction.dueDate }}</h3>        
        <mat-list-item>
          <img matListAvatar src="https://source.unsplash.com/random/100x100" alt="...">
          <span matLine class="mat-body-2"> {{transaction.description}} </span>
          <p matLine class="col col-6 left-align">
            <span class="mat-body-1"> {{transaction.categoryName}} </span>
            <br>
            <span class="mat-caption"> {{transaction.accountName}} </span>
          </p>
          <p class="col col-6 right-align">
            <span class="mat-subheading">{{ transaction.amount | currency:'BRL':'symbol' }}</span>
          </p>
        </mat-list-item>       
      </div>
    </mat-list>

<ng-template #loading>Loading...</ng-template>

So here: <mat-list *ngIf="transactions | async; let transactions;else loading">

I have *ngIf with async pipe to show mat-list if transactions has loaded. Next let user statement if true creating a local template variable that Angular assigns the value from the Observable.

Otherwise else loading tells Angular if the condition is not met to show the loading template.

Check it out this excelent post from @coryrylan: https://coryrylan.com/blog/angular-async-data-binding-with-ng-if-and-ng-else

0
votes

I also faced a similar kind of error, and, in order to solve it, I looked up a bit and realised I declared the URL in wrongly.

The declaration should be something like this

private urlVariable = 'http://sampleurl.com';