Erstellen eines iTunes-Players mit Angular

Mit Angular meinen wir Angular 2.

In diesem Lernprogramm erstellen wir eine iTunes-Suchanwendung. Die App verwendet die offene iTunes JSONP-API, um nach Künstlern zu suchen und Alben dieses Künstlers in einem Kendo-UI-Raster anzuzeigen. Jedes Album wird erweitert, um ein Detailraster anzuzeigen, das alle Titel enthält. Jeder Titel kann mit Web Audio abgespielt werden.

Sie können die fertige Anwendung anzeigen und den gesamten Code auf GitHub abrufen. Wenn Sie an irgendeinem Punkt nicht weiterkommen, empfehle ich, das abgeschlossene Projekt als Referenz herunterzuladen.

Voraussetzungen

  • Die Winkel-CLI

Erstellung der App

Erstellen Sie zunächst eine neue Anwendung, in der Sie Sass als bevorzugte Stilsprache angeben. Wenn Sie Sass nicht kennen, machen Sie sich keine Sorgen. Sie können immer noch einfaches altes CSS in Sass-Dateien schreiben. Die Verwendung von Sass gibt uns nur die Möglichkeit, Stilbibliotheken von Drittanbietern einfach einzubinden. Die Angular-CLI verdrahtet alle erforderlichen Build-Schritte.

> ng new itunes-search -style=scss && cd itunes-search

Führen Sie die Anwendung aus und lassen Sie sie geöffnet. Die Anwendung läuft normalerweise auf Port 4200. Eine ausführlichere Erklärung finden Sie in diesem Artikel.

> ng serve

Installieren Sie als Nächstes das Bootstrap-Sass-Paket von npm.

> npm install bootstrap-sass --save

Fügen Sie die Bootstrap-Sass-Referenzen zu Ihrem Projekt in 05 hinzu Datei.

/* You can add global styles to this file, and also import other style files */

/* Bootstrap CSS And Icon Font */

$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
@import "~bootstrap-sass/assets/stylesheets/bootstrap";

Die App wird automatisch aktualisiert. Aufgrund der von Bootstrap verwendeten serifenlosen Schriftart sieht es etwas anders aus.

Fügen Sie das folgende Markup zu 18 hinzu .

<div class="container">
	<h1>iTunes Search</h1>
	<!-- Artist Component Will Go Here -->
	<!-- Audio Player Component Will Go Here -->
</div>

Erstellen eines Dienstes

Erstellen Sie als Nächstes einen Dienst, der die JSON-API von iTunes Search aufruft. Der Angular Style Guide empfiehlt, diese in einem „freigegebenen“ Ordner abzulegen, erstellen Sie also den freigegebenen Ordner unter 22 .

> mkdir src/app/shared

Erstellen Sie den Dienst mit den Angular-CLI-Generatoren, die Komponenten, Dienste und dergleichen aufbauen.

> ng generate service shared/itunes

Öffnen Sie die 31 Datei und fügen Sie den Code hinzu, der 49 importiert Unterstützung für Angular 2, die 55 und 67 Methoden von rxjs und stellt eine Funktion bereit, die den HTTP-Aufruf an den iTunes-Dienst sendet und ein Promise zurückgibt.

import { Injectable } from '@angular/core';
import { Jsonp } from '@angular/http';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/toPromise';

const API = {
  SEARCH: 'https://itunes.apple.com/search?',
  LOOKUP: 'https://itunes.apple.com/lookup?'
}

@Injectable()
export class ItunesService {

  constructor(private jsonp: Jsonp) {
  }

  public search(searchTerm): Promise<any> {
    return this.jsonp.get(`${API.SEARCH}callback=JSONP_CALLBACK&media=music&country=US&entity=musicArtist&term=${searchTerm}`)
      .toPromise()
      .then(data => data.json().results)
      .catch(this.handleError)
  }

  private handleError(error: any): Promise<any> {
    console.log(error);
    return Promise.reject(error.message || error);
  }
}

Die 77 Modul muss auch in 87 eingefügt werden Datei, sonst steht sie hier im Dienst nicht zur Verfügung.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

// Include the JSONP module for JSONP support
import { HttpModule, JsonpModule } from '@angular/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,

    // include the JSONP module so it can be used in the application
    JsonpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Komponenten erstellen

Jetzt fügen wir die Künstlerkomponente hinzu, die die Suchleiste und Künstlerergebnisse enthält. Es ruft auch den iTunes-Dienst auf, um nach Künstlern zu suchen.

> ng generate component artist

Dadurch wird ein 98 erstellt Mappe. Es fügt auch die Komponente in 105 ein Datei, damit sie in der Anwendung verwendet werden kann. Die Angular-CLI erledigt all dies, wenn Sie 113 verwenden Befehl.

Fügen Sie das folgende Markup zu 125 hinzu Datei.

<div class="row">
  <div class="col-xs-12">
    <input type="search" #searchBox (keyup)="search(searchBox.value)" class="form-control input-lg well" placeholder="Type to search for artist...">
  </div>
</div>
<div class="row">
  <div class="col-sm-4" *ngIf="searchResults.length > 0">
    <h3>Search Results</h3>
    <p *ngFor="let artist of searchResults">
      <a id="{{ artist.artistId }}" href="#" (click)="getAlbums(artist.artistId, artist.artistName)">{{ artist.artistName }}</a>
    </p>
  </div>
  <div class="col-xs-12" [ngClass]="{'col-sm-8': searchResults.length > 0 }">
    <h3>{{ selectedArtist }}</h3>
    <!-- App Album Component Goes Here -->
  </div>
</div>

Dieses Markup erstellt das Suchfeld und ein zweispaltiges Layout für die Künstlersuchergebnisse auf der linken Seite. Wenn der Benutzer auf einen Künstler klickt, werden alle Alben dieses Künstlers in einem Raster auf der rechten Seite angezeigt.

Öffnen Sie die 131 Datei. Fügen Sie den erforderlichen Code hinzu, um die Bindung von 143 zu unterstützen Datei. Es benötigt einen 153 -Methode zum Aufrufen des iTunes-Dienstes, wenn der Benutzer eintippt, sowie eine Sammlung von 166 die auf der Seite angezeigt wird, und schließlich ein 177 Ereignis, das ausgelöst wird, wenn der Benutzer auf ein Künstlerergebnis klickt.

import { Component } from '@angular/core';
import { ItunesService } from '../shared/itunes.service';

@Component({
  selector: 'app-artist',
  templateUrl: './artist.component.html',
  providers: [ItunesService]
})
export class ArtistComponent {

  searchResults: Array<any> = [];
  artistId: number = 0;

  selectedArtist: string;

  constructor(private itunesService: ItunesService) { }

  search(searchTerm) {
    this.itunesService.search(searchTerm).then(results => {
      this.searchResults = results;
    });
  }

  getAlbums(artistId: number, artistName: string) {
    this.artistId = artistId;
    this.selectedArtist = artistName;
  }
}

Aufrufen des iTunes-Dienstes

Jetzt fügen wir die Möglichkeit hinzu, Alben nach Interpreten vom iTunes-Dienst abzurufen. Öffnen Sie 187 Datei und fügen Sie Folgendes hinzu.

private _albums: Array<any> = [];
private _artistId: number = 0;

// Get Albums Method 
public getAlbums(artistId: number): Promise<any> {

  if (artistId == this._artistId) return new Promise(resolve => resolve(this._albums));

  this._artistId = artistId;

  return this.jsonp.get(`${API.LOOKUP}callback=JSONP_CALLBACK&entity=album&id=${artistId}`)   
  .toPromise()
  .then(data => {
    this._albums = data.json().results.filter(results => {
      return results.wrapperType == 'collection'
    });

    return this._albums;
  })
  .catch(this.handleError);
}

Dieser Code enthält eine neue Funktion, 196 das Alben nach Künstler-ID von der iTunes-API abruft. Außerdem werden Aufrufe an 200 zwischengespeichert falls die Funktion wiederholt mit den gleichen Parametern aufgerufen wird. Benutzeroberflächen tun dies häufig.

Erstellen Sie als Nächstes die Album-Komponente mit dem Angular-CLI-Komponentengenerator.

> ng generate component album

Hinzufügen in der Kendo-Benutzeroberfläche

Fügen Sie nun das Kendo UI Grid für Angular hinzu. Bevor Sie dies tun, stoppen Sie den Dev-Server, indem Sie 213 drücken . Dies ist bei der Kendo-Benutzeroberfläche erforderlich, um sicherzustellen, dass Dateien, die kopiert werden müssen, nicht verwendet werden.

> npm login --registry=https://registry.npm.telerik.com/ --scope=@progress
> npm install --save @progress/kendo-angular-grid
> npm install --save @progress/kendo-data-query
> npm install -S @telerik/kendo-theme-default
> ng serve

Verweisen Sie auf das Standarddesign der Kendo-Benutzeroberfläche in 222 Datei.

@import "~@telerik/kendo-theme-default/styles/packages/all";

Fügen Sie das Kendo UI Grid zu 239 hinzu Datei.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule, JsonpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { ArtistComponent } from './artist/artist.component';

// Import Kendo UI Grid
import { GridModule } from '@progress/kendo-angular-grid';

@NgModule({
  declarations: [
    AppComponent,
    ArtistComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    JsonpModule,

    // Register the Kendo UI Grid
    GridModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Fügen Sie nun das folgende Markup zum 245 hinzu Datei.

<kendo-grid 
  [data]="view" 
  >
  <kendo-grid-column field="artworkUrl60" title=" " width="95">
    <template kendoCellTemplate let-dataItem>
      <img src="{{ dataItem.artworkUrl60 }}">
    </template>
  </kendo-grid-column>
  <kendo-grid-column field="collectionName" title="Album Title"></kendo-grid-column>
  <kendo-grid-column field="releaseDate" title="Release Date">
    <template kendoCellTemplate let-dataItem>
      <p>{{ dataItem.releaseDate | date }}</p>
    </template>
  </kendo-grid-column>
  <div *kendoDetailTemplate="let dataItem">
    <!-- Tracks Component Goes Here -->
  </div>
</kendo-grid>

Alben nach Künstler abrufen

Fügen Sie die Logik für die Album-Komponente hinzu, die Alben vom iTunes-Dienst basierend auf einer Künstler-ID einzieht.

import { Component, Input } from '@angular/core';
import { ItunesService } from '../shared/itunes.service';
import { GridDataResult } from '@progress/kendo-angular-grid';

@Component({
  selector: 'app-album',
  templateUrl: './album.component.html',
  providers: [ItunesService]
})
export class AlbumComponent {

  private view: GridDataResult;

  @Input() 
  set artistId(artistId: number) {
    this._artistId = artistId;

    // get the albums for this artist
    this.getAlbums();
  }
  get artistId() { return this._artistId }

  constructor(private itunesService: ItunesService) { }

  getAlbums() {
    this.itunesService.getAlbums(this.artistId).then((results: Array<any>) {
      this.view = {
        data: results,
        total: results.length
      }
    });
  }
}

Der 256 ermöglicht es uns, eine Variable in der Album-Komponente anzugeben, die von der übergeordneten Komponente festgelegt werden kann, in diesem Fall der Artist-Komponente. Wir verwenden einen Setter, um sicherzustellen, dass jedes Mal, wenn die Artist-Komponente eine Artist-ID festlegt, die Alben-Komponente den Inhalt des Rasters aktualisiert, indem sie 260 aufruft . Dies ist eine Möglichkeit, wie Angular-Komponenten miteinander kommunizieren können. Weitere Informationen finden Sie unter Komponenteninteraktion in der Angular-Dokumentation.

Fügen Sie die Albumkomponente zu 275 hinzu Datei. Beachten Sie die Verwendung von 286 , die an 299 übergeben wird .

<div class="row">
  <div class="col-xs-12">
    <input type="search" #searchBox (keyup)="search(searchBox.value)" class="form-control input-lg well" placeholder="Type to search for artist...">
  </div>
</div>
<div class="row">
  <div class="col-sm-4" *ngIf="searchResults.length > 0">
    <h3>Search Results</h3>
    <p *ngFor="let artist of searchResults">
      <a id="{{ artist.artistId }}" href="#" (click)="getAlbums(artist.artistId, artist.artistName)">{{ artist.artistName }}</a>
    </p>
  </div>
  <div class="col-xs-12" [ngClass]="{'col-sm-8': searchResults.length > 0 }">
    <h3>{{ selectedArtist }}</h3>
    <!-- App Album-->
    <app-album [artistId]="artistId" *ngIf="artistId > 0"></app-album>
  </div>
</div>

Jetzt zeigt die Alben-Komponente Alben an, wenn ein Künstler ausgewählt wird.

Durch die Ergebnisse blättern

Fügen Sie Paging zum Grid hinzu, indem Sie das Grid auf pageable setzen, die Seitengröße definieren (wie viele Datensätze pro Seite angezeigt werden), den Skip-Parameter (wie viele Datensätze vom Beginn der Sammlung zu überspringen) und den 301 Ereignis auf der Grid-Komponente in 315 .

<kendo-grid 
  [data]="view" 
  [pageSize]="pageSize"
  [skip]="skip"
  [pageable]="true"
  (pageChange)="pageChange($event)"
  >
  .... Grid Content Omitted For Berevity ....
</kendo-grid>

Ändern Sie 327 Datei zur Handhabung des 335 Ereignis durch Aufrufen des 342 -Methode erneut und trimmen Sie das resultierende Array auf die richtigen Elemente für die aktuelle Seite.

import { Component, Input } from '@angular/core';
import { ItunesService } from '../shared/itunes.service';
import { GridDataResult, PageChangeEvent } from '@progress/kendo-angular-grid';
import { SortDescriptor, orderBy } from '@progress/kendo-data-query';

@Component({
  selector: 'app-album',
  templateUrl: './album.component.html',
  providers: [ItunesService]
})
export class AlbumComponent {

  view: GridDataResult;
  _artistId: number = 0;

  // controls grid paging settings
  private pageSize: number = 5;
  private skip: number = 0;

  @Input() 
  set artistId(artistId: number) {
    this._artistId = artistId;

    // get the albums for this artist
    this.getAlbums();
  }
  get artistId() { return this._artistId }


  constructor(private itunesService: ItunesService) { }

  getAlbums() {
    this.itunesService.getAlbums(this.artistId).then((results: Array<any>) {
      this.view = {
        // slice the album result to get only the selected page of data
        data: results.slice(this.skip, this.skip + this.pageSize),
        total: results.length
      }
    });
  }

  // fires when the user changes pages in the grid
  protected pageChange(event: PageChangeEvent): void {
    this.skip = event.skip;
    this.getAlbums();
  }
}

The Grid hat jetzt Paging-Unterstützung.

Detaillierte Streckenergebnisse anzeigen

Neben jeder Zeile befindet sich ein kleines „+“-Symbol, das darauf hinweist, dass Sie die Zeile erweitern können, um weitere Informationen anzuzeigen. Im Moment passiert nichts. Das gewünschte Verhalten besteht darin, alle verfügbaren Spuren für das ausgewählte Element anzuzeigen. Dazu benötigen wir eine Tracks-Komponente.

Fügen Sie zuerst einen 358 hinzu Methode zum 362 Datei, die alle Tracks für eine bestimmte Album-ID zurückgibt.


public getTracks(albumId: number): Promise<any> {
  return this.jsonp.get(`${API.LOOKUP}callback=JSONP_CALLBACK&entity=song&id=${albumId}`)
  .toPromise()
  .then(data => {
    return data.json().results.filter(result => {
      return result.wrapperType == 'track';
    });
  })
  .catch(this.handleError)
}

Erstellen Sie die Tracks-Komponente mit der Angular-CLI.

> ng generate component track

Öffnen Sie den 372 Datei und fügen Sie das folgende Markup hinzu.

<kendo-grid
      [data]="view"
      [scrollable]="'none'"
    >
  <kendo-grid-column width="50">
    <template kendoCellTemplate let-dataItem>      
      <!-- Track Control Component Goes Here -->
    </template>
  </kendo-grid-column>
  <kendo-grid-column field="trackCensoredName" title="Track Name">
  </kendo-grid-column>
</kendo-grid>

Fügen Sie den folgenden Code zu 387 hinzu Datei. Beachten Sie die Verwendung des 394 -Parameter, um die Album-ID an die Tracks-Komponente zu übergeben. Dies ist genau dieselbe Funktion, die verwendet wurde, um die Künstler-ID von der Künstlerkomponente an die Albumkomponente zu übergeben.

import { Component, OnInit, Input } from '@angular/core';
import { ItunesService } from '../shared/itunes.service';

@Component({
  selector: 'app-track',
  templateUrl: './track.component.html',
  styleUrls: ['./track.component.scss'],
  providers: [ItunesService]
})
export class TrackComponent implements OnInit {

  view: Array<any>

  @Input() 
  set collectionId(collectionId: number) {
    this.getTracks(collectionId);
  }

  constructor(private itunesService: ItunesService) { }

  ngOnInit() {
  }

  private getTracks(collectionId: number) {
    this.itunesService.getTracks(collectionId).then(result => {
      this.view = result;
    });
  }

}

Fügen Sie nun die Tracks-Komponente zu 407 hinzu Datei.

<kendo-grid 
  [data]="view" 
  [pageSize]="pageSize"
  [skip]="skip"
  [pageable]="true"
  (pageChange)="pageChange($event)"
  >
  <kendo-grid-column field="artworkUrl60" title=" " width="95">
    <template kendoCellTemplate let-dataItem>
      <img src="{{ dataItem.artworkUrl60 }}">
    </template>
  </kendo-grid-column>
  <kendo-grid-column field="collectionName" title="Album Title"></kendo-grid-column>
  <kendo-grid-column field="releaseDate" title="Release Date">
    <template kendoCellTemplate let-dataItem>
      <p>{{ dataItem.releaseDate | date }}</p>
    </template>
  </kendo-grid-column>
  <div *kendoDetailTemplate="let dataItem">
    <!-- Tracks Component -->
    <app-track [collectionId]="dataItem.collectionId"></app-track>
  </div>
</kendo-grid>

Audio abspielen

Die iTunes-API stellt für jeden Titel eine URL zu einem Audiobeispiel bereit. Der Browser kann die Web Audio API verwenden, um diese Tracks abzuspielen.

Erstellen Sie eine Player-Komponente, die den Audio-Player für die Anwendung steuert.

> ng generate component player

Fügen Sie dem 414 das folgende Markup hinzu Datei.

<audio #player="" style="display: none" (ended)="playerEnded()">

Fügen Sie den folgenden Code zu 425 hinzu Datei. Dies behandelt die Einstellung der Audioquelle (src) für den Player sowie die Handhabung, was zu tun ist, wenn ein Track-Sample beendet wird.

import { Component, OnInit, ViewChild } from '@angular/core';

@Component({
  selector: 'app-player',
  templateUrl: './player.component.html',
  styleUrls: ['./player.component.scss']
})
export class PlayerComponent implements OnInit {

  @ViewChild('player') playerRef;
  player: any;

  constructor() {}

  ngOnInit() {
    this.player = this.playerRef.nativeElement;
  }

  playerEnded() {
    // handle event
  }
}

Fügen Sie die Player-Komponente zu 430 hinzu . Es gibt nur eine Audiosteuerung für die gesamte Anwendung. Alle Tracks verwenden diesen Audioplayer, wenn der Benutzer auf das „Play“-Symbol neben einem Track klickt.

<div class="container">
    <h1>iTunes Search</h1>
    <!-- Artist Component -->
  <app-artist></app-artist>
    <!-- Audio Player Component -->
  <app-player></app-player>
</div>

Erstellen Sie als Nächstes eine Track-Steuerungskomponente, die Play/Pause-Schaltflächen für jeden Track erstellt und mit der Player-Komponente kommuniziert.

> ng generate component track/track-control

Beachten Sie, dass diese Komponente im Track Component-Ordner verschachtelt ist. Dies liegt daran, dass sie zwar nicht direkt voneinander abhängig sind, aber sehr eng miteinander verwandt sind und daher logisch in eine hierarchische Struktur gehören.

Fügen Sie das folgende Markup zu 445 hinzu Datei, um die Wiedergabe-/Pause-Symbole mit der Bootstrap-Symbolschriftart anzuzeigen.

<div>
  <span *ngif="!isPlaying" class="glyphicon glyphicon-play" aria-hidden="true" (click)="playTrack()"></span>
  <span *ngif="isPlaying" class="glyphicon glyphicon-pause" aria-hidden="true" (click)="pauseTrack()"></span>
</div>

Fügen Sie den Code zu 457 hinzu , das den Status des Titels (isPlaying) sowie die Klickereignisse der Wiedergabe-/Pause-Symbole steuert.

import { Component, OnDestroy, Input } from '@angular/core';

@Component({
  selector: 'app-track-control',
  templateUrl: './track-control.component.html',
  styleUrls: ['./track-control.component.sass']
})
export class TrackControlComponent {

  isPlaying: boolean = false;
  @Input() public track: any;

  constructor() { }

  playTrack() {
    this.isPlaying = true;
  }

  pauseTrack() {
    this.isPlaying = false;
  }

}

Fügen Sie nun die Track Control-Komponente zu 466 hinzu Datei.

<kendo-grid
      [data]="view"
      [scrollable]="'none'"
    >
  <kendo-grid-column width="50">
    <template kendoCellTemplate let-dataItem>      
      <!-- Track Control Component -->
      <app-track-control [track]="dataItem"></app-track-control>
    </template>
  </kendo-grid-column>
  <kendo-grid-column field="trackCensoredName" title="Track Name">
  </kendo-grid-column>
</kendo-grid>

An diesem Punkt wird jeder Track eine Play/Pause-Schaltfläche anzeigen. Jeder Track kennt auch seine eigene URL für das entsprechende Audio-Sample. Die Track Control-Komponente kann jedoch noch nicht mit der Player-Komponente kommunizieren, sodass während die Schaltfläche von einem Wiedergabe- in einen angehaltenen Zustand wechselt, tatsächlich kein Audio wiedergegeben wird.

Um diese Kommunikation zu erleichtern, verwenden wir einen Shared Service. Erstellen Sie einen neuen Dienst namens Player Service.

> ng create service shared/player

Der Player-Dienst enthält einige rxjs-Abonnements, die andere Komponenten abonnieren können. Auf diese Weise können Komponenten Ereignisse auslösen und andere Komponenten auf diese Ereignisse reagieren, obwohl sie überhaupt nicht wissen, dass die andere Komponente existiert. Weitere Informationen zur Kommunikation über gemeinsame Dienste finden Sie in der offiziellen Angular-Dokumentation.

Fügen Sie den folgenden Code zu 479 hinzu Datei.

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/subject';

@Injectable()
export class PlayerService {

  private playTrackSource = new Subject<string>();
  private pauseTrackSource = new Subject();
  private trackEndedSource = new Subject();

  playTrack$ = this.playTrackSource.asObservable();
  pauseTrack$ = this.pauseTrackSource.asObservable();
  trackEnded$ = this.trackEndedSource.asObservable();

  playTrack(previewUrl: string) {
    this.playTrackSource.next(previewUrl);
  }

  pauseTrack() {
    this.pauseTrackSource.next();
  }

  trackEnded() {
    this.trackEndedSource.next();
  }

}

Fügen Sie den Dienst in 489 ein Datei. Dieser lauscht, wenn ein Titel ausgewählt wird, und spielt die Datei ab. Es stoppt auch die Wiedergabe einer Datei, wenn der Benutzer auf die Pause-Schaltfläche klickt. Schließlich löst es ein Ereignis aus, wenn das Sample vollständig abgespielt ist.

import { Component, OnInit, ViewChild } from '@angular/core';
import { PlayerService } from '../shared/player.service';

@Component({
  selector: 'app-player',
  templateUrl: './player.component.html',
  styleUrls: ['./player.component.scss']
})
export class PlayerComponent implements OnInit {

  @ViewChild('player') playerRef;
  player: any;

  constructor(private playerService: PlayerService) {

    playerService.playTrack$.subscribe(previewUrl => {
      this.playTrack(previewUrl);
    });

    playerService.pauseTrack$.subscribe(() => {
      this.pauseTrack();
    })

  }

  ngOnInit() {
    this.player = this.playerRef.nativeElement;
  }

  playTrack(previewUrl) {
    this.player.src = previewUrl;    
    this.player.play();
  }

  pauseTrack() {
    this.player.pause();
  }

  playerEnded() {
    this.playerService.trackEnded();
  }
}

Ändern Sie 493 Datei, um auch auf Trigger-Track-Ereignisse über den Dienst zu hören.

import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { PlayerService } from '../../shared/player.service';
import { Subscription } from 'rxjs/subscription';

@Component({
  selector: 'app-track-control',
  templateUrl: './track-control.component.html',
  styleUrls: ['./track-control.component.sass']
})
export class TrackControlComponent implements OnInit, OnDestroy {

  isPlaying: boolean = false;
  @Input() public track: any;

  playSub: Subscription;
  endedSub: Subscription;

  constructor(private playerService: PlayerService) {
    this.playSub = playerService.playTrack$.subscribe(
      track => {
        this.isPlaying = false;
      });

    this.endedSub = playerService.trackEnded$.subscribe(() => {
      this.isPlaying = false;
    })
  }

  ngOnInit() {
  }

  ngOnDestroy() {
    // clean up any subscriptions we aren't using anymore
    this.playSub.unsubscribe();
    this.endedSub.unsubscribe();
  }

  playTrack() {
    this.playerService.playTrack(this.track.previewUrl);
    this.isPlaying = true;
  }

  pauseTrack() {
    this.playerService.pauseTrack();
    this.isPlaying = false;
  }

}

Zuletzt fügen Sie den Dienst in 508 ein . Diese Komponente ist die oberste Ebene sowohl für die Player-Komponente als auch für die Track-Steuerungskomponente. Wenn Sie den Dienst hier einfügen, wird er automatisch irgendwo weiter unten im Komponentenbaum eingefügt, wenn darauf verwiesen wird.

import { Component } from '@angular/core';
import { PlayerService } from './shared/player.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  providers: [PlayerService]
})
export class AppComponent {

}

Jetzt spielt die App Musik ab, wenn auf die Wiedergabeschaltfläche neben einem Titel geklickt wird. Darüber hinaus wird durch das Abspielen eines anderen Titels während der Wiedergabe eines Titels der richtige Zustand für die Wiedergabeschaltfläche sowohl für den neu wiedergegebenen Titel als auch für den zuvor wiedergegebenen Titel festgelegt. So verwaltet Angular 2 ziemlich komplexe Zustände.

Holen Sie sich die Kendo-UI für Angular-Komponenten

In diesem Artikel haben Sie gesehen, wie Sie ein Raster mit Daten füllen, Paging verwenden und sogar Detailraster verdrahten. The Grid kann viel und mehr als nur das. Ich empfehle dringend, sich die Grid-Tutorials anzusehen.

Die fertige App können Sie hier sehen. Der gesamte Code aus diesem Artikel ist auf GitHub verfügbar. Befolgen Sie die README-Anweisungen, um es einzurichten und auf Ihrem eigenen Computer auszuführen.