0

I've been working on a personal app. My goal is to have a search and delete users using Observables. For search functionality I have used this idea, this is how I implemented:

export class UserComponent implements OnInit {
  users: Observable<User[]>;
  private searchTerms = new Subject<string>();

  ngOnInit(): void {
    this.setUsers();
  }

  private setUsers(): void {
    this.users = 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 => term   // switch to new observable each time the term changes
        // return the http search observable
        ? this.userService.search(term)
        // or the observable of all users if there was no search term
        : this.userService.search(''))
      .catch(() => {
        this.response = -1;
        return Observable.of<User[]>([]);
      });
  }
}

For delete functionality I use this:

private deleteSubject = new Subject();

delete(user: User): void {
  this.userService
      .delete(user)
      .then(() => {
        this.deleteSubject.next('');
      })
      .catch(() => {
        console.log('error');
      });
}

private setUsers(): void {
  ... // here comes the search functionality shown above
  this.subscription = this.deleteSubject.subscribe(
    (term: string) => this.users = this.userService.search(''),
    (err) => console.log(err)
  );
}

The problem that I faced with this implementation is that after I delete an user my search functionality is broken because I lost the subscriber for searchTerms because I reassigned this.users. So I've been searching and found that I can use merge operator to append another subject, follow this idea. Sadly I'm facing a problem with the implementation. I tried this:

delete(user: User): void {
  ...
  // change
  this.deleteSubject.next('');
  // with
  this.deleteSubject.next({op: 'delete', id: user.id});
}

private setUsers(): void {
... 
  this.users.merge(this.deleteSubject)
    .startWith([])
    .scan((acc: any, val: any) => {
      if (val.op && val.op === 'delete') {
        let index = acc.findIndex((elt: any) => elt.id === val.id);
        acc.splice(index, 1);
        return acc;
      } else {
        return acc.concat(val);
    }
  });

But my scan operator is never execute because this.deleteSubject doesn't have a subscriber for it. I know how to create and associate a subscriber to my this.deleteSubject but don't know how to mix it with my merge operator. Also see that it's getting a bit complex, I guess it should be another way to get this done. Comments are appreciated.

Please take a look at my plunker, hope gets a bit clear. I've simulated the calls to my services using a memory array userList.

Community
  • 1
  • 1
Gabriel Muñumel
  • 1,876
  • 6
  • 34
  • 57

1 Answers1

0

I fixed my problem, I had to do two changes:

  1. Assign this.users.merge(this.deleteSubject) to this.users
  2. In the else block for scan operator change return acc.concat(val); to return val;

I updated my plunker if you want to take a look. Cheers.

Gabriel Muñumel
  • 1,876
  • 6
  • 34
  • 57