how to add an object to an observable of array
Asked Answered
C

1

6

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

Cadent answered 15/8, 2018 at 18:46 Comment(3)
You're looking for a BehaviorSubject for your sevice. Doesn't take up much more computation resources, and maintains push notifications to observable streams as well as keeps the value.Esqueda
can you give an example?Cadent
Deborah's answer should have you covered now with the update.Esqueda
D
16

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.

Dhu answered 15/8, 2018 at 18:53 Comment(3)
I can't do that, the first time I can get to this books is inside the function addBook, I need to either be able to add to the subject or to get from the subject the list that was given and added to it the new bookCadent
@z-bagley: For this to work, the BehaviorSubject needs to be initialized. I'll edit.Dhu
The updated versions of this answer is well done, thanks!Introit

© 2022 - 2024 — McMap. All rights reserved.