Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the service called twice in this angular 2 component?

I have here the component code, when I am subscribing to the observable the service is called twice, however if I subscribe to the Behaviorsubject it is only triggered once,

I can see on my logs that those are the result, please see my code below for my component the method subscribeToMap() method is called on ngOninit.

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

import { Observable }        from 'rxjs/Observable';
import { Subject }           from 'rxjs/Subject';

// Observable class extensions
import 'rxjs/add/observable/of';

// Observable operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';

import { HeroSearchService } from './hero-search-service';
import { Hero } from './../hero';

@Component({
  selector: 'hero-search',
  templateUrl: './hero-search.component.html',
  styleUrls: [ './hero-search.component.css' ],
  providers: [HeroSearchService]
})
export class HeroSearchComponent implements OnInit {
  heroes: Observable<Hero[]>;
  private searchTerms = new Subject<string>();

  constructor(
    private heroSearchService: HeroSearchService,
    private router: Router) {}

  // Push a search term into the observable stream.
  search(term: string): void {
    this.searchTerms.next(term);
    console.log("new " + term);
  }



  ngOnInit(): void {
    this.heroes = this.searchTerms
      .debounceTime(300)        // wait 300ms after each keystroke before considering the term
      .distinctUntilChanged()   // ignore if next search term is same as previous
      .switchMap(term => {
        return term   // switch to new observable each time the term changes
        // return the http search observable
        ? this.heroSearchService.search(term)
        // or the observable of empty heroes if there was no search term
        : Observable.of<Hero[]>([])})
      .catch(error => {
        // TODO: add real error handling
        console.log(error);
        return Observable.of<Hero[]>([]);
      });
      this.subscribeToMap();
  }

  subscribeToMap(): void{
     this.heroes.subscribe(() => console.log("called twice"));
     this.searchTerms.subscribe(() => console.log("called once"));
  }


  gotoDetail(hero: Hero): void {
    let link = ['/detail', hero.id];
    this.router.navigate(link);
  }
}

Here is the code for my service

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

import { Observable }     from 'rxjs/Observable';
import 'rxjs/add/operator/map';

import { Hero }           from './../hero';

@Injectable()
export class HeroSearchService {

  constructor(private http: Http) {}

  search(term: string): Observable<Hero[]> {
    console.log("service is called");
    return this.http
               .get(`api/heroes/?name=${term}`)
               .map(response => response.json().data as Hero[]);
  }
}

thank you ver much!!!

like image 461
Lego_blocks Avatar asked Aug 16 '17 15:08

Lego_blocks


1 Answers

When subscription is implemented properly it has nothing to do with "unsubscribe" method, Observable, etc. This behavior is by design of Angular itself.

https://www.reddit.com/r/Angular2/comments/59532r/function_being_called_multiple_times/d95vjlz/

If you're running in development mode, it will run the function at least twice. since in development mode it does a check, changes, then rechecks to verify, where production mode only does the first check, assuming you've done your quality assurance and resolved any values the get changed post checking.

P.S. This is probably the next issue you will face to in Dev Mode :)

Angular2 change detection "Expression has changed after it was checked"

like image 157
Anonymous Avatar answered Nov 14 '22 21:11

Anonymous