0
votes

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, i.e.: 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;
    });
  }
}
1
If you use the async pipe, it must provide a stream of arrays. - user663031
@torazaburo async pipe did not solve the problem. - Francisco
You're returning 'view' from map instead of 'obj'? - BeaverusIV

1 Answers

0
votes

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.