Observable subscription on onInit only runs once

i have table with names and an input tag that when value changes it filters the content of the table. The data cames from and http request made on a service.

I have three scenarios:

1- If i subscribe to this.ds.getDrogas() only on ngOninit() the table show all the content but filter doesn´t work. 2- If i subscribe to this.ds.getDrogas() only on filterName() the table starts empty but when i change once the value of the input y starts to work well. If i delete input´s content the table shows all the data and if i write something again the filter works. 3- If i subscribe in both it works as expected. The table starts showing all the content and when input value changes the filter works.

I know that the code inside ngOnInit() only runs once but a subscription shouldn´t keep listening to observable changes?

I appreciate your help in advance.

Service Side:

getDrogas(): Observable <HttpResponses> {
    return this.http.get<HttpResponses>(this.apiUrl +'/drogas')
  }

Table-Component.ts:

    ngOnInit{
        this.ds.getDrogas().pipe(
        map((data)=> data.data
        .filter(element=> element.identificacion.nombre.startsWith(this.contador))))
        .subscribe(res=> {this.dataDroga= res; console.log('Ejecutado con valor de contador'+ 
        this.contador)});
    }

   contador: string =''

   filterName(){
   this.ds.getDrogas()
   console.log(this.dataDroga)
   }

Table-Component.html:

<input  type="text" [(ngModel)]='contador' (ngModelChange)='filterName()'>

Upvotes: 1

Views: 2006

Answers (1)

Dmitrii Makarov
Dmitrii Makarov

Reputation: 749

this.ds.getDrogas() - returns an Observable. And Angular does not request data from the server without a subscription. You subscribe to it in the ngOnInit() - that's why you get the initial data.

I suggest using the denounceTime operator with the subject inside ngModelChange handler to prevent API calls on every change. It will look like this:

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {

  filterValue$ = new BehaviorSubject('');
  filterValue = '';

  constructor(private api: ApiSerive) {}

  ngOnInit(): void {
    this.filterValue$.pipe(
      debounceTime(DEBOUNCE_TIME),
      switchMap(filterValue => this.api.getData().pipe(
        map(dataFromServer => filterData(dataFromServer, filterValue)),
      )),
      /* UNSUBSCRIBE HERE on compoennt destroy */
      tap(filteredData => {
        console.log(filteredData);
        /* LOGIC OF UPDATE TABLE */
      }),
    ).subscribe();
  }

  onFilterChanged(value: string): void {
    console.log(value);
    this.filterValue$.next(value);
  }
}

function filterData(dataFromServer: any, filterValue): any {
  // SOME LOGIC HERE
  return dataFromServer;
}

Full code is here https://stackblitz.com/edit/angular-txwgmk

P.S.

Don't forget to unsubscribe from observables in your component.

I hope it helps!

Upvotes: 1

Related Questions