5
\$\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\$
  • \$\begingroup\$ uset Subject instead which do not require initial value \$\endgroup\$ – diEcho Mar 24 '18 at 18:47
2
\$\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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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