11
\$\begingroup\$

Is it possible to get rid of the BehaviourSubject to have an Observable with an initial value? Another thing I don't like is that I'm using getValue() and then modify this value and push it with next back to the Observable. Maybe there is a more elegant way to get the same thing?

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

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

@Injectable()
export class UserProvider {

  users$: Observable<{ id: string; name: string }[]>;

  private usersSource: BehaviorSubject<{ id: string; name: string }[]>;

  constructor() {
   this.usersSource = new BehaviorSubject<any>([
     { id: '111', name: 'Jack' },
     { id: '222', name: 'John' },
     { id: '333', name: 'Foo' },
   ]);
   this.users$ = this.usersSource.asObservable();
  }

  addUser(user: { id: string; name: string }) {
    const currentUsers = this.usersSource.getValue();
    currentUsers.push(user);
    this.usersSource.next(currentUsers);
  }

  removeUser(userId: string) {
    const currentUsers = this.usersSource.getValue();
    const index = currentUsers.findIndex(user => user.id === userId);
    if (index !== -1) {
      if (this.selectedUserIdSource.getValue() === currentUsers[index].id) {
        this.selectedUserIdSource.next(null);
      }
      currentUsers.splice(index, 1);
      this.usersSource.next(currentUsers);
    }
  }
}
\$\endgroup\$
1
  • \$\begingroup\$ uset Subject instead which do not require initial value \$\endgroup\$
    – xkeshav
    Commented Mar 24, 2018 at 18:47

2 Answers 2

5
\$\begingroup\$

This is a really good question -- starred it! I am not very experienced with RxJs, but I believe your code around BehaviorSubject and Observable is as concise as possible.

BehaviourSubject itself is "subscribable" (just like an Observable) but it's a really bad practice to expose it directly to the consumer, i.e. your separation of users$ and usersSource is a right thing to do. Exposing Observable is okay because it's designed to be read-only.

usersSource.getValue() is inevitable in your code, unless you decide to keep the usersSource state as a local field, but IMO it does not do any good in this scenario. Having state to be stored as a part of the BehaviorSubject is handy.


There are minor style things that could be improved in the code, but that's unrelated to RxJs, so I'll not comment on that.


Update 1

Just a few months ago I was not aware of .startsWith() which seems to be an answer to a part of your question:

const neverButStartsWithZero = Rx.Observable
                                .never()
                                .startWith(0);
// Emits 0
const subscription1 = neverButStartsWithZero
                        .subscribe(value => console.log('subscription1:', value));

const threeEventsWithExtraZero = Rx.Observable
                                .of(1, 2, 3)
                                .startWith(0);
// Emits 0, 1, 2, 3
const subscription2 = threeEventsWithExtraZero
                        .subscribe(value => console.log('subscription2:', value));
\$\endgroup\$
0
0
\$\begingroup\$

I know its an old post but you could also do a getter for your example

get users$() {
  return this.usersSource$.asObservable();
}
\$\endgroup\$
1
  • 3
    \$\begingroup\$ Welcome to Code Review! This may be the start of an answer, but it's not much of a review yet. Please see our help page on How to write a good answer. \$\endgroup\$
    – Mast
    Commented Oct 23, 2020 at 11:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.