franco
franco

Reputation: 697

Angular Rxjs: Observable does not display on view

I have the following code that is supposed to display the length of an audio file:

ngAfterViewInit() {
    this.duration$ = fromEvent(this.player.nativeElement, 'loadeddata').pipe(
      map((event: any) => {
        return this.convertDuration(event.target.duration);
      }));
  }

But it won't display on my HTML that looks like this: <div>{{ duration$ | async }}</div>

What could be the problem here? I tried to subscribe in my component and this works:

this.duration$.subscribe(x => console.log(x));

Initialization: duration$: Observable<string>;


After looking at @EliyaCohen's demo, I realized that the reason why my code doesn't work is because I have ChangeDetectionStrategy.OnPush enabled. I think my issue now is how to trigger a change detection without calling detectChanges() or markForChange() if that's possible.

Here is my demo.

Upvotes: 0

Views: 643

Answers (2)

Andrei Gătej
Andrei Gătej

Reputation: 11934

I think it should work this way:

@Component({
  /* ... */
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class PlayerComponent implements AfterViewInit {
  duration$: Observable<string>;

  @ViewChild("video", { static: true }) player: ElementRef<HTMLElement>;
  @Input() source: string;

  ngOnInit() {
    this.duration$ = fromEvent(this.player.nativeElement, "loadeddata").pipe(
      map((event: any) => event.target.duration)
    );
  }
}

I'm using { static: true }, since the video element does not depend on any conditions, like ngIf.

The problem with ngAfterViewInit is that the async pipe will create its subscriptions before this lifecycle hook takes place. This means that by the time ngAfterViewInit is invoked, the async pipe will have already figured out its subscriptions, but since this happened before this hook, there was no subscription, so nothing to subscribe to.

Upvotes: 1

Eliya Cohen
Eliya Cohen

Reputation: 11458

I couldn't reproduce your problem, so I made a simple demo that might help (don't mind the errors of codesandbox).

  1. I created a <video> tag
  2. I bound the video tag and called it imported it from @ViewChild
  3. on ngAfterViewInit I used the exact code you did, but without convertDuration since I'm not sure what it does exactly.
  4. I subscribed in the HTML to the observable and it worked.

If you could share a little bit of your code, I might be able to reproduce it.

Upvotes: 0

Related Questions