Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert a plain string[] into a Observable<string[]> and concat it to another Observable<string[]> using RxJS 5

Tags:

angular

rxjs5

I am trying to convert a plain string[] into a Observable<string[]> and concat it to an existing Observable<string[]>.

I will then use an angular2 async pipe in order to display the Observable.

Here is my code:

import {Injectable} from "angular2/core";
import {Observable} from "rxjs/Observable";
import 'rxjs/Rx';


@Injectable()
export class AppService {

    constructor() {
        console.log('constructor', 'appService');
        this.constructSomeObservable();
    }

    someObservable$:Observable <string[]>;

    constructSomeObservable() {
        this.someObservable$ = Observable.create(observer => {
            const eventSource = new EventSource('/interval-sse-observable');
            eventSource.onmessage = x => observer.next(JSON.parse(x.data));
            eventSource.onerror = x => observer.error(console.log('EventSource failed'));
            return () => {
                eventSource.close();
            };
        });

        this.someObservable$.subscribe(
            theStrings=> {
                console.log(theStrings);
                //Somehow convert the plain array of strings to an observable and concat it to this.someObservable$ observable...
            },
            error=>console.log(error)
        );
    }
}

Can anyone please help?

Furthermore, I want to ensure that the service instance Observable<string[]> is continuously updated as the EventSource is called repeatedly. Is my subscribe logic in the right place?

edit 1: I tried to use RxJS concat operator as follows:

    this.someObservable$.subscribe(
        theStrings=> {
            console.log(theStrings);
            this.someObservable$ = this.someObservable$.concat(Observable.create(theStrings));
        },
        error=>console.log(error)
    );
 }

together with the angular2 async pipe:

<ul>
    <li *ngFor="#s of appService.someObservable$ | async">
       a string: {{ s }}
    </li>
</ul>

and nothing gets displayed on the page; the strings just get displayed on the console...

What I am getting wrong?

edit 2: The app is available on github here

edit 3: I have taken into account Thierry's advice, especially the use of the async pipe in order to subscribe as well as the usage of the scan operator.

The only remaining issue now is that I need to click on the router link in order for the strings to render on the template... The template does not update automatically...

See project on github and relevant tag: https://github.com/balteo/demo-angular2-rxjs/tree/36864628/536299

like image 611
balteo Avatar asked Apr 26 '16 11:04

balteo


1 Answers

I would leverage the scan operator to do that. Here is a sample:

@Component({
  selector: 'app'
  template: `
    <div>
      <div *ngFor="#elt of someObservable$  | async">{{elt.name}</div>
    </div>
  `
})
export class App {
  constructor() {
    this.someObservable$ = Observable.create((observer) => {
      const eventSource = new EventSource('/interval-sse-observable');
      eventSource.onmessage = x => observer.next(JSON.parse(x.data));
      eventSource.onerror = x => observer.error(console.log('EventSource failed'));
      return () => {
        eventSource.close();
      };
    })
    .startWith([])
    .scan((acc,value) => acc.concat(value));
  }
}

Here is the corresponding plunkr: https://plnkr.co/edit/St7LozX3bnOBcoHaG4uM?p=preview.

See this question for more details:

  • Angular 2 AsynPipe isn't working with an Observable
like image 61
Thierry Templier Avatar answered Nov 15 '22 08:11

Thierry Templier