How to push to Observable of Array in Angular 4? RxJS

26,004

Solution 1

As you said in comments, I'd use a Subject.

The advantage of keeping articles observable rather than storing as an array is that http takes time, so you can subscribe and wait for results. Plus both components get any updates.

// Mock http
const http = {
  get: (url) => Rx.Observable.of(['article1', 'article2']) 
}

const articles = new Rx.Subject();

const fetch = () => {
  return http.get('myUrl').map(x => x).do(data => articles.next(data))
}

const add = (article) => {
  articles.take(1).subscribe(current => {
    current.push(article);
    articles.next(current);
  })
}

// Subscribe to 
articles.subscribe(console.log)

// Action
fetch().subscribe(
  add('article3')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.2/Rx.js"></script>

Solution 2

Instead of storing the whole observable, you probably want to just store the article array, like

articles: Article[]

fetch() {
    this.get(url).map(...).subscribe(articles => this.articles)
}

Then you can manipulate the articles list using standard array manipulation methods.

If you store the observable, it will re-run the http call every time you subscribe to it (or render it using | async) which is definitely not what you want.

But for the sake of completeness: if you do have an Observable of an array you want to add items to, you could use the map operator on it to add a specified item to it, e.g.

observable.map(previousArray => previousArray.concat(itemtToBeAdded))

Share:
26,004
simon_www
Author by

simon_www

Updated on February 27, 2020

Comments

  • simon_www
    simon_www about 4 years

    I have a property on my service class as so:

    articles: Observable<Article[]>;
    

    It is populated by a getArticles() function using the standard http.get().map() solution.

    How can I manually push a new article in to this array; One that is not yet persisted and so not part of the http get?

    My scenario is, you create a new Article, and before it is saved I would like the Article[] array to have this new one pushed to it so it shows up in my list of articles.

    Further more, This service is shared between 2 components, If component A consumes the service using ng OnInit() and binds the result to a repeating section *ngFor, will updating the service array from component B simultaneously update the results in components A's ngFor section? Or must I update the view manually?

    Many Thanks, Simon

  • Richard Matsen
    Richard Matsen over 6 years
    Since articles is an observable, the components subscribe to it (in javascript) or use it directly on a template with the async filter. So since they connect via a reactive pipeline, they will update automatically whenever the Subject is updated.
  • Richard Matsen
    Richard Matsen over 6 years
    Note, you can vary the type of Subject used depending on when components do the subscribing. A plain Subject is probably fine for components that subscribe in ngOnInit or in the template, but if they subscribe late in the app flow (say ComponentB is on a secondary page), you may want to use a ReplaySubject which stores the last value and 'replays' it for new subscriptions.
  • Richard Matsen
    Richard Matsen over 6 years
    I tend to think of Subject as the socket that components plug into, but it has no storage. ReplaySubject is a socket with (configurable) storage, and BehaviorSubject has storage for one item but can take an initial value - useful for providing some default value for components before the fetch has filled in it's value.
  • simon_www
    simon_www over 6 years
    Marked this as complete because I can see this is the right answer. I am however having problems with it working in my app. Would you be happy to continue a discussion with me to try and solve the issue i'm having?
  • Richard Matsen
    Richard Matsen over 6 years
    Sure thing. How do you want to do it -is it something you can add to the question?
  • simon_www
    simon_www over 6 years
    When there's enough comments SO lets you start a discussion separately. However as it happens I may have it sorted. I was subscribing to the result of the http get, not the Subject array. Now I'm subbed to the Subject array, everything is updating as expected :) Thanks though!