0

I am trying to implement a table with a input filter in a Angular 11 project. The table is populated by a SERVICE:

export class Service{
 url='myUrl';

 http; 

 constructor(private http:HttpClient){
  this.http=http
 } 

 loadAll(): Observable<Author[]> {
  return this.http.get<Author[]>(this.url)
}

in my component I have a variable "filteredAuthors$" that will represent all data showed in table.

export class MyComponent{
 authors$:Observable<Author[]>
 filteredAuthors$:Observable<Author[]>

 //form that receive the input filter
 filterForm:FormControl

 constructor(private service:Service){
  this.authors$=service.loadAll()

  filterForm=new ForControl('')

  this.filteredAuthors$=filterForm.valueChanges.pipe(
   startWith('').withLatestFrom(this.authors$),
   map(
    ([typedValue, authors])=>!typedValue ? authors : 
     authors.filter(author=>author.name.includes(typedValue))
)))}}

With this code, I always start my table with 0 rows and after I type something on input, then the filter works great. Another weird thing is that when I replace my service with a mock observable created with "of" method, then the table start with all rows and is filtered after the first input in filter. What I am not seeing? The author type is:

export type Author={
 id:string,
 name:string
}
Flavio Silva
  • 17
  • 1
  • 3
  • Yes, but the service is receiving the data from my json-server. When I debug I see that my "authors$" observable have received the values, but it was not mapped to filteredAuthors$ observable. The filteredAuthors$ will not emit any value until I type something in the filterForm. – Flavio Silva Dec 21 '20 at 20:42
  • When you "debug" you do the exact same thing as with `of` - you skip async sideeffects because you "pause the execution" where normally program wont stop. You need to be carefull when debugging async code. – Antoniossss Dec 21 '20 at 20:44
  • withLatestFrom could block the begin of the stream, but that's the reason I used "startWith" operator. – Flavio Silva Dec 21 '20 at 20:44
  • No, it is second in line and will block artificially emmited value (from startWith) as well. Keep in mind, that this is a pipe - there is no skipping operators. – Antoniossss Dec 21 '20 at 20:45
  • You can see how placement of startsWith in the pipe matters here https://stackblitz.com/edit/rxjs-m8gjd8?file=index.ts – Antoniossss Dec 21 '20 at 20:52

1 Answers1

0
  1. of is synchronous so you are skipping all possible async sideeffects of delayed observable - like a web call.
  2. withLatestFrom will block untill given observable emits event. Therfore, until authors$ is done (assumig a web call), processing down the pipe is supressed. (2nd example from here confirms that https://www.learnrxjs.io/learn-rxjs/operators/combination/withlatestfrom)
Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • Well, if the async is the problem, could be a way to I wait until my service get data and then keep the stream? – Flavio Silva Dec 21 '20 at 20:49
  • yes, for example fetch authors, and `switchMap` to the input value changes. At this point you will already have all authors - which can be stored as field. – Antoniossss Dec 21 '20 at 20:54
  • After 15 hours studying about synchronous vs asynchronous observables, I finally understood the diference about a observable created with "of"(syncronous) vs http.get(asynchronous). Your answer make me get the fundamental error I was doing. Thanks! – Flavio Silva Dec 22 '20 at 12:04