简体   繁体   中英

Angular2 observable stream to *ngFor

I have this code :

objs = []

getObjs() {
    let counter = 0
    this.myService.getObjs()
      .map((obj) => {
        counter = counter > 5 ? 0 : counter;
        obj.col = counter;
        counter++;
        return view
      })
      .subscribe((obj) => {
          console.log(obj);
          this.objs = obj;
          // I tried this too :
          // this.zone.run(() => {
          //   this.objs.push(obj);
          // });
    }
    , (err)=> console.warn('error in stream', err));
}

this.myService.getObjs is a stream listening to an SSE event. Here's the code in case it helps :

  getObjs(){
      var es = new EventSource(this.API + '/stream');
      return Observable.create((observer: any) => {
            es.onmessage = (event) => {
                let msg = JSON.parse(event.data)[0];
                if(msg === "complete"){
                    console.log("received 'complete' signal from server");
                    es.close();
                    observer.complete();
                }
                observer.next(msg);
            };
        });
  }

I call this method in ngOnInit. And then I expect the template to update as soon as the events arrive. Template :

<div class="col-md-2">
    <thumbnail-dirictive [v]="view" *ngFor="let obj of ( objs | column: 0 )"></orbit-thumbnail>
</div>

Now, this logs as expected. Stream events arrive and are logged. What doesn't happen is that the template is not sequentially updated, ie: first-come-first-served.

I know I can pass the stream as a named variable and in template use the async pipe, I also tried passing the toArray() method and get all values once they all arrived (what I would expect in the complete callback to the observer), I also tried reduce to an array buffer where objs are concatenated to last but didn't get any luckier... Can anyone post a working example of a stream not regular in time into an ngFor ?

Edit 1 (stating angular version) : package.js :

{
  "dependencies": {
    "@angular/common": "2.0.0",
    "@angular/compiler": "2.0.0",
    "@angular/core": "2.0.0",
    "@angular/forms": "2.0.0",
    "@angular/http": "2.0.0",
    "@angular/platform-browser": "2.0.0",
    "@angular/platform-browser-dynamic": "2.0.0",
    "@angular/router": "3.0.0",
    "@angular/router-deprecated": "2.0.0-rc.2",
    "@angular/upgrade": "2.0.0"
  }
}

Edit 2 (the columns pipe code, registered in app module ) :

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'column'})
export class columnPipe implements PipeTransform {
  transform(views, col: number): Array {
    return views.filter((view) => {
      return view.col === col;
    });
  }
}

As far as I can tell your code looks fine. If this.objs = obj; assigns correct values I'd start looking some place else:

  • ngOnInit is called before the components template is created. However this shouldn't be problem if you haven't played with Component's ChangeDetectorRef .

  • Dump objs and then objs|column:0 inside:

     <div class="col-md-2"> {{ objs|json }} {{ objs|column:0|json }} <thumbnail-dirictive ... /> 

    to make sure it contains what you think and that the column pipe does what it should (it's hard to tell whether it works correctly without knowing you data structure).

  • In your template you have:

     <div class="col-md-2"> <thumbnail-dirictive ...></orbit-thumbnail> 

    This is obviously incorrect. Are you sure the problem isn't here?

If none of these help, try making some basic plnkr of jsfiddle where we can see how it fails.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM