How to add New Item onto Observable of type Array?

160 views Asked by At

I am working on angular tour of heroes example. There is a feature to add a new hero to the existing list of heroes. My add hero method in hero.service.ts is as below:

addNewHero(hero : Hero) : Observable<Hero> {
    console.log(hero)
   return this._http.post<Hero>(this.url,hero).pipe(
    tap(res => this._service.addMessage(`new hero is ${hero.name} added`)),
    catchError(error => this.handleerror('adding a hero'))

   )
  }

addHero method in Heroescomponent class is as below :

export class HeroesComponent implements OnInit {

  heroes : Observable<Array<Hero>>;
  selectedHero: Hero;

  constructor(private _service : HeroService,private _router : Router) { }

  ngOnInit() {
    this.heroes = this._service.getHeroes()
  }

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }

  details(id : Number) {
    this._router.navigate(['heroes',id])
  }

  **addHero(name : String){
    console.log(name)
    this._service.addNewHero({ name } as Hero).subscribe((res : Hero) => {
      this.heroes = this._service.getHeroes()
     
    })
  }**
}

Heroes.HTML file is as below:

<h2>My Heroes</h2>
<div>
  <input type="text" #heroname>
  <button (click) = "addHero(heroname.value)">Add</button>
</div>
<ul class="heroes">
  <li *ngFor="let hero of heroes | async">
    <a routerLink = "/detail/{{hero.id}}"
    style = "text-decoration : none"><span class="badge">{{hero.id}}</span> {{hero.name}}</a> 
  </li>
</ul>

I am using the heroes variable with type Observable<Hero[]>.

so, whenever I am adding a new hero I want to add a newly added hero to the existing heroes. But, I am not able to do it as there is no push method for observable of arrays. So, I am calling getHeroes method again to refresh the list to display newly added items. Is there any workaround to add the item to the Data type Observable<Array> instead of hitting the server again

1

There are 1 answers

0
Robert Dempsey On

You can use a Subject, like so:

export class HeroesComponent implements OnInit {

    heroes = new Subject<Array<Hero>>();
    heroes$ = this.heroes.asObservable();
    selectedHero: Hero;
  
    constructor(private _service : HeroService,private _router : Router) { }
  
    ngOnInit() {
      this._service.getHeroes().subscribe(heroes => this.heroes.next(heroes))
    }
  
    onSelect(hero: Hero): void {
      this.selectedHero = hero;
    }
  
    details(id : Number) {
      this._router.navigate(['heroes',id])
    }
  
    addHero(name : String){
      
      this._service.addNewHero({ name } as Hero).pipe(
          withLatestFrom(this.heroes)
      ).subscribe(([newHero, currentHeroes]) => {
        this.heroes.next(currentHeroes.concat(newHero))
       
      })
    }
  }

A Subject provides the next method, which allows you to emit a new value, which will then become the value of the heroes$ Observable, as the heroes Subject is its source.