'Angular 2: TypeError: is not a function

I'm working on an Angular 2 application, scaffolded with angular-cli RC0. I've setup an AuthGuard, to protect some routes. this guard, implements CanActivate and if not logged in redirect the user to the login page and an Angular Material2 MdSbackBar should appear with a custom message. Here the AuthGuard:

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(
    private router: Router,
    private authService: AuthService,
    private growlerService: GrowlerService
  ) { }

  canActivate(): boolean {
    if (this.authService.isAuthenticated()) {
      return true;
    } else {
      this.router.navigate(['auth/login']);
      this.growlerService.growl('Autenticazione richiesta', GrowlerMessageType.Error);
      return false;
    }
  }

}

Here the growler service that is called in the CanActivate method as shown above:

@Injectable()
export class GrowlerService {

  constructor() { }

  growl: (message: string, type: GrowlerMessageType) => void;

}

Finally the actual function in growler component

export class GrowlerComponent {

  constructor(
    private snackBar: MdSnackBar,
    private growlerService: GrowlerService
  ) {
    growlerService.growl = this.growl.bind(this);
  }

  growl(message: string, type: GrowlerMessageType): void {
    const growlerConfig = new MdSnackBarConfig();
    growlerConfig.duration = 3000;
    growlerConfig.extraClasses = this.growlerTypeClass(type);
    this.snackBar.open(message, null, growlerConfig);
  }

}

Everything is imported/exported correctly and growler works when not called from the CanActivate. In order to build this i've followed this example, replacing the growler component, in the example, with an angular material component. GrowlerTypeClass is a private method defined in growler component but that is not the problem. Problem is that when user is not logged in and canActivate try to call the growler service i get the following error in console:

EXCEPTION: Uncaught (in promise): TypeError: this.growlerService.growl is not a function
TypeError: this.growlerService.growl is not a function
    at AuthGuard.webpackJsonp.259.AuthGuard.canActivate

Thanks in advance for you help.



Solution 1:[1]

In GrowlerComponent, you are defining the growlerService.growl function yourself. It looks like that is by design (of the Growler library), in order to implement some sort of Growler specific callback mechanism. But you don't have that in your AuthGuard. It looks like you may want to add: growlerService.growl = this.growl.bind(this); ...to the AuthGuard constructor as well. And then implement that method (similar to in GrowlerComponent).

Solution 2:[2]

the auth guard is running before your growler component can bind to the growler service. This is a design flaw. consider instead:

@Injectable()
export class GrowlerService {

  constructor() { }
  private growlSource = new Subject<{message: string, type: GrowlerMessageType}>();
  growl$ = this.growlSource.asObservable();
  growl(message: string, type: GrowlerMessageType) {
    this.growlSource.next({message, type});
  };

}

export class GrowlerComponent {

  constructor(
    private snackBar: MdSnackBar,
    private growlerService: GrowlerService
  ) {
    growlerService.growl$.subscribe(({message, type}) => this.growl(message, type));
  }

  growl(message: string, type: GrowlerMessageType): void {
    const growlerConfig = new MdSnackBarConfig();
    growlerConfig.duration = 3000;
    growlerConfig.extraClasses = this.growlerTypeClass(type);
    this.snackBar.open(message, null, growlerConfig);
  }

}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Will
Solution 2 bryan60