how to add an object to an observable of array

Yedidya kfir picture Yedidya kfir · Aug 15, 2018 · Viewed 8.6k times · Source

I have an angular project with a service called BookService.

private books: Subject<Book[]>;

getBookList(skip:number = 0,limit:number = 0): Subject<Book[]> {
  return this.books;
}

addBookToList(book:Book) {
}

this service help me to monitor the changes in a list of books, I also want to be able to add a single book to the list using the addBookToList function but I dont know how to add a single book the this observable (the subject-observer) is it possible to add a single book

Answer

DeborahK picture DeborahK · Aug 15, 2018

A subject is a type of observable. As such, it is a stream. You can add an item (such as a book) to the stream and the item will be broadcast to any observers of the stream.

However, it is not like a normal array. Once the item is added to the stream and broadcast, it will no longer be accessible in the subject's "list". It will only be accessible in the components that subscribed to this Subject.

To add something to the subject's stream:

 this.books.next(book);

This adds it to the stream and broadcasts it to all existing subscribers.

If you want to keep a "cache" of books, consider defining your books as a simple array and not as the Subject.

Here is an example of one of my services:

export class MovieService {
  private movies: Movie[];

  private selectedMovieSource = new Subject<Movie | null>();
  selectedMovieChanges$ = this.selectedMovieSource.asObservable();

  constructor(private http: HttpClient) { }

  changeSelectedMovie(selectedMovie: Movie | null): void {
    this.selectedMovieSource.next(selectedMovie);
  }

  // more code here
}

Notice that my movies is an actual array that contains my "cache" of movies. The Subject is set as a separate property.

You can see my complete example here: https://github.com/DeborahK/MovieHunter-communication/tree/master/MH-4

Check out the movie.service.ts and the movie components that call it.

UPDATE:

Another option would be to instead use a BehaviorSubject which maintains the value of your Subject and can be referred to at any time:

private books: BehaviourSubject<Book[]> = new BehaviorSubject<Book[]>([]);

getBookList(skip:number = 0,limit:number = 0): BehaviorSubject<Book[]> {
  return this.books;
}

addBookToList(book:Book) {
  // apply the current value of your books Subject to a local variable
  let myBooks = this.books.getValue();
  // push that book into your copy's array
  myBooks.push(book);
  // apply the local updated array value as your new array of books Subject
  this.books.next(myBooks);
}

Note that this adds the entire array of books to the stream each time.