0
votes

Error message

I have no idea why an undefined[] would be assigned to a string as I was following Tours of Heroes tutorial: https://angular.io/tutorial/toh-pt6#http

Last time I fixed this error by starting at the homepage URL because I think it was trying to get a string non-existing string but when I added more code from the http section, I can't even start from the homepage (dashboard view.)

heroes.component.ts

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  heroes : Hero[];  
  constructor(private heroService: HeroService) {   // generate an instance of the HeroService
  }

  getHeroes() : void{
    this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes);     //async - subscribe passes emitted array to callback which sets property
                                                                                //i.e. when heroes (alias) is retrieved, set it to heroes property
  }

  ngOnInit() {
    this.getHeroes();
  }

  add(name: string): void {
  name = name.trim();
  if (!name) { return; }
  this.heroService.addHero({ name } as Hero)
    .subscribe(hero => {
      this.heroes.push(hero);
    });
}

}

hero.service.ts

...
import { MessageService } from './message.service';

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

@Injectable()
export class HeroService {
  private heroesUrl = 'api/heroes'; //URL to web api

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

  getHeroes() : Observable<Hero[]> {
    return this.http.get<Hero[]>(this.heroesUrl)
        .pipe(
            tap(heroes => this.log(`fetched heroes`)),
            catchError(this.handleError('getHeroes',[]))
        );                  
  }

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

  /** GET hero by id. Will 404 if id not found */
    getHero(id: number): Observable<Hero> {
    const url = `${this.heroesUrl}/${id}`;
    return this.http.get<Hero>(url).pipe(
        tap(_ => this.log(`fetched hero id=${id}`)),
        catchError(this.handleError<Hero>(`getHero id=${id}`))
    );
}

updateHero (hero: Hero): Observable<any> {
    return this.http.put(this.heroesUrl, hero, httpOptions).
    pipe(
        tap(_ => this.log(`updated hero id=${hero.id}`)),
        catchError(this.handleError<any>('updateHero'))
    );
}

/** POST: add a new hero to the server */
addHero (hero: Hero): Observable<Hero> {
  return this.http.post<Hero>(this.heroesUrl, hero, httpOptions).pipe(
    tap((hero: Hero) => this.log(`added hero w/ id=${hero.id}`)),
    catchError(this.handleError<Hero>('addHero'))
  );
}

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);
  };
}

}

message.service.ts

import { Injectable } from '@angular/core';

@Injectable()
export class MessageService {

  messages: string[] = [];

  add(message : string){
    this.messages.push(message);
  }

  clear(){
    this.messages = [];
  }

}

dashboard.component.ts

...
import { HeroService} from '../hero.service';
@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: [ './dashboard.component.css' ]
})
export class DashboardComponent implements OnInit {
  heroes: Hero[];

  constructor(private heroService: HeroService) { }

  ngOnInit() {
    this.getHeroes();
  }

  getHeroes(): void {
    this.heroService.getHeroes()
      .subscribe(heroes => this.heroes = heroes.slice(1, 5));
  }
}

hero-detail.component.ts

...
import { HeroService} from '../hero.service';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {

  @Input() hero : Hero; 

  constructor(
    private route : ActivatedRoute,
    private location : Location,
    private heroService : HeroService
  ) { }

  ngOnInit() {
    this.getHero();
  }

  getHero(): void{
    const id = +this.route.snapshot.paramMap.get('id'); // route.snapshot- static image of route info after component is created, 'paramMap'- all param names of route
    this.heroService.getHero(id).subscribe(hero => this.hero = hero);
  }

  goBack(): void{
    this.location.back();
  }
  save(): void{
    this.heroService.updateHero(this.hero)
        .subscribe(() => this.goBack());
  }
}
1

1 Answers

0
votes

It should be

 messages: Array<string> = [];