1

I keep getting an 404 error on my media player as the "sermon.fileName" property is made available after the component loads on screen. How can I work around this?

enter image description here

sermon.component.ts

import { Component, OnInit, ChangeDetectorRef, AfterViewChecked } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ApiProvider } from '../../providers/api/api';
import { Breakpoints, BreakpointState, BreakpointObserver } from '@angular/cdk/layout';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment';
import { SermonModule } from './sermon';
import { VgAPI } from 'videogular2/core';

@Component({
  templateUrl: './sermon.component.html',
  providers: [ApiProvider]
})
export class SermonComponent implements OnInit, AfterViewChecked {
  constructor(private apiProvider: ApiProvider,
    private route: ActivatedRoute,
    private breakpointObserver: BreakpointObserver,
    private cdRef: ChangeDetectorRef
  ) { }

  isMobile: Observable<BreakpointState>;
  public id: String;
  public sermon = {} as SermonModule.Sermon;
  api: VgAPI;

  ngOnInit() {
    this.id = this.route.snapshot.paramMap.get('id');
    this.getSermon(this.id);
    this.isMobile = this.breakpointObserver.observe(Breakpoints.Handset);
  }

  ngAfterViewChecked() {
    this.cdRef.detectChanges();
  }

  onPlayerReady(api: VgAPI) {
    this.api = api;

    this.api.getDefaultMedia().subscriptions.ended.subscribe(
      () => {
        this.api.getDefaultMedia().currentTime = 0;
      }
    );
  }

  getSermon(id: String) {
    this.apiProvider.getSermon(id).subscribe((data: SermonModule.Sermon) => {
      if (environment.production === false) {
        console.log(data);
        console.log(new SermonObject().deserialize(data));
      }
      this.sermon = new SermonObject().deserialize(data);
    });
  }
}

class SermonObject implements SermonModule.Serializable<SermonModule.Sermon> {
  id: string;
  name: string;
  fileName: string;
  speaker: string;
  description: string;
  tags: string[];
  date: string;
  sermonSession: string;

  deserialize(input) {
    this.id = input.id;
    this.name = input.name;
    this.fileName = input.fileName;
    this.speaker = input.speaker;
    this.description = input.description;
    this.tags = input.tags;
    this.date = input.date;
    this.sermonSession = input.sermonSession;
    return this;
  }
}

sermon.component.html

<vg-player style="height: 50px;">
  <vg-controls>
    <vg-play-pause></vg-play-pause>
    <vg-playback-button></vg-playback-button>
    <vg-time-display vgProperty="current" vgFormat="mm:ss"></vg-time-display>
    <vg-scrub-bar>
      <vg-scrub-bar-current-time></vg-scrub-bar-current-time>
      <vg-scrub-bar-buffering-time></vg-scrub-bar-buffering-time>
    </vg-scrub-bar>
    <vg-time-display vgProperty="left" vgFormat="mm:ss"></vg-time-display>
    <vg-time-display vgProperty="total" vgFormat="mm:ss"></vg-time-display>
    <vg-mute></vg-mute>
    <vg-fullscreen></vg-fullscreen>
  </vg-controls>
  <audio #media [vgMedia]="media" preload="auto">
    <source [src]="sermon?.fileName" type="audio/mp3">
  </audio>
</vg-player>

api.provider.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';
import { map } from 'rxjs/operators';

@Injectable()
export class ApiProvider {
  private apiUrl = environment.apiUrl;
  private bookUrl = 'assets/data/books.json';
  private speakerUrl = 'assets/data/speakers.json';

  constructor(private httpClient: HttpClient) { }

  public getAllSermons() {
    return this.httpClient.get(this.apiUrl + '/sermon').pipe(map((data: any) => data.data)
    );
  }

  public getSermon(id: String) {
    return this.httpClient.get(this.apiUrl + '/sermon/' + id).pipe(map((data: any) => data.data)
    );
  }


  public getAllBooks() {
    return this.httpClient.get(this.bookUrl).pipe(map((data: any) => data)
    );
  }

  public getAllSpeakers() {
    return this.httpClient.get(this.speakerUrl).pipe(map((data: any) => data)
    );
  }

  public getAllSessions() {
    return this.httpClient.get(this.apiUrl + '/sermon/session').pipe(map((data: any) => data.data)
    );
  }
}
methuselah
  • 12,766
  • 47
  • 165
  • 315

1 Answers1

1

You've got two options (or more). One would be to use a route resolver, to resolve the sermon before the component loads. Another would be to use an *ngif to only show the <audio> element if sermon is available:

<audio *ngIf="sermon" #media [vgMedia]="media" preload="auto">
  <source [src]="sermon.fileName" type="audio/mp3">
</audio>
Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
  • Hi thanks for your response. Using *ngIf doesn't work. The element loads before the data is resolved. I've tried using a route resolver as well and seeing the same issue. – methuselah Oct 23 '18 at 08:52
  • @methuselah then I don't think that request is coming from the code you posted. If you open chrome dev tools network tab, you can see the stack trace from the request. That will give you more info about the origin – Poul Kruijt Oct 23 '18 at 08:54