Angular4 Angular-material2 Table and Dialog: MySportsFeeds API Part 6

Angular-material2 dataTable.

This app uses angular material2 dataTable module to show baseball player data.

  • Run npm install --save @angular/material @angular/cdk
  • Import it to app.module import {MdTableModule} from '@angular/material;
  • Set it up in app.component define the table columns and pass data to the table.
  • Call the dataTable in the app.component.html
//app.compoent.ts

import { Component, ViewChild, Inject, OnInit } from '@angular/core';
import { DataSource } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import { Http, Response, RequestOptions, Headers, Request, RequestMethod } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';

let headers = new Headers({ "Authorization": "Basic " + btoa('username' + ":" + 'password') });
let options = new RequestOptions({ headers: headers });
let url = 'https://api.mysportsfeeds.com/v1.1/pull/mlb/2017-regular/cumulative_player_stats.json?position=P&sort=STATS.Pitching-NP.D&limit=275';

export interface Data {}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {

   cumulativePlayerStatData: Array<any>;
   showData: Array<any>;
   displayedColumns = [
    'id',
    'pitches',
    'strikeouts',
    'pitcherWalks',
    'inningsPitched',
    'pitchesPerInning',
    'pitcherWildPitches',
    'pickoffAttempts'
  ];
  dataSource: MyDataSource;

   constructor(private http: Http) {}
  
    loadData() {
      this.http.get(url, options)
     .map(response => response.json())
      .subscribe(res => {
        console.log(res['cumulativeplayerstats'].playerstatsentry, 'got player info res!');
        this.cumulativePlayerStatData = res['cumulativeplayerstats'].playerstatsentry;
      });

      this.showData = this.cumulativePlayerStatData;

      //This fills the dataTable with data
      this.dataSource = new MyDataSource(this.showData);

   }
   
   ngOnInit() {
    this.loadData();
   }


}

export class MyDataSource extends DataSource <Data> {

  constructor(private datas: Data[]) {
    super();
  }

  connect(): Observable <Data[]> {
    return Observable.of(this.data); 
  }

  disconnect() {}

}
//app.compoent.html

<div id="exampleContainer" class="example-container example-container-fixed mat-elevation-z8">
  <md-table #table [dataSource]="dataSource">
    <!-- Rank Column and Name of Player -->
    <ng-container cdkColumnDef="id">
      <md-header-cell *cdkHeaderCellDef>
        Rank 
      </md-header-cell>
      <md-cell *cdkCellDef="let i=index; let data;">
          <b>{{i+1}}. </b>{{ data.player.FirstName + ' ' + data.player.LastName + ' - ' + data.team.Abbreviation}}
      </md-cell>
    </ng-container>
    <!-- Pitches Column -->
    <ng-container cdkColumnDef="pitches">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pitch Count </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.PitchesThrown['#text']}} </md-cell>
    </ng-container>
    <!-- StrikeOuts Column -->
    <ng-container cdkColumnDef="strikeouts">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Strike Outs </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.PitcherStrikeouts['#text']}} </md-cell>
    </ng-container>
    <!-- PitcherWalks Column -->
    <ng-container cdkColumnDef="pitcherWalks">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pitcher Walks </md-header-cell>
      <md-cell *cdkCellDef="let data">
        {{data.stats.PitcherWalks['#text']}}
      </md-cell>
    </ng-container>
    <!-- InningsPitched Column -->
    <ng-container cdkColumnDef="inningsPitched">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Innings Pitched </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.InningsPitched['#text']}}</md-cell>
    </ng-container>
    <!-- pitchesPerInning Column -->
    <ng-container cdkColumnDef="pitchesPerInning">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pitches Per Inning </md-header-cell>
      <md-cell *cdkCellDef="let data">
        {{data.stats.PitchesPerInning['#text']}}
      </md-cell>
    </ng-container>
    <!-- PitcherWildPitches Column -->
    <ng-container cdkColumnDef="pitcherWildPitches">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Wild Pitches </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.PitcherWildPitches['#text']}}</md-cell>
    </ng-container>
    <!-- PickoffAttempts Column -->
    <ng-container cdkColumnDef="pickoffAttempts">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pickoff Attempts </md-header-cell>
      <md-cell *cdkCellDef="let data">
        {{data.stats.PickoffAttempts['#text']}}
      </md-cell>
    </ng-container>
    <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
    <md-row *cdkRowDef="let data; columns: displayedColumns; let i=index;"></md-row>
  </md-table>
</div>
  • My example shows the older naming conventions for MdTable which is now called MatTable. The main difference is the import would look like this import {MatTableModule} from '@angular/material';

Angular-material2 mdDialog module.

In a single page app modals are a cool way to show some specific data in the same view. In this app there are 275 rows of individual baseball players and their stats. I have made each row enabled to be clicked to pop up a modal with more specific real time stats.

This app uses angular material2 pop up modal to show baseball player data.

  • Run npm install --save @angular/material @angular/cdk
  • Import it to app.module import {MdDialogModule} from '@angular/material;
  • Set it up in app.component and make an open function for the modal.
  • Create a click event in app.component.html to pass in the player data and open the modal from the dataTable. <md-row (click)="open($event, data)" *cdkRowDef="let data; columns: displayedColumns; let i=index;"></md-row>
  • Import the MyDialog component to app.module. import { AppComponent, MyDiaog } from './app.component'; and add MyDialog to the ngModule.
//app.module.ts

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


@NgModule({
  declarations: [
    AppComponent,
    MyDialog
  ],
  imports: [
    MdTableModule,
    MdDialogModule
  ]
  providers: [FirebaseService],
  entryComponents: [
    MyDialog
  ],
  bootstrap: [AppComponent]
})



```ts

//app.compoent.ts

import { Component, ViewChild, Inject, OnInit } from '@angular/core';
import { MdDialog, MdDialogRef, MD_DIALOG_DATA } from '@angular/material';
import { DataSource } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import { Http, Response, RequestOptions, Headers, Request, RequestMethod } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';

let headers = new Headers({ "Authorization": "Basic " + btoa('username' + ":" + 'password') });
let options = new RequestOptions({ headers: headers });
let url = 'https://api.mysportsfeeds.com/v1.1/pull/mlb/2017-regular/cumulative_player_stats.json?position=P&sort=STATS.Pitching-NP.D&limit=275';

export interface Data {}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {

   cumulativePlayerStatData: Array<any>;
   showData: Array<any>;
   displayedColumns = [
    'id',
    'pitches',
    'strikeouts',
    'pitcherWalks',
    'inningsPitched',
    'pitchesPerInning',
    'pitcherWildPitches',
    'pickoffAttempts'
  ];
  dataSource: MyDataSource;

   constructor(private http: Http, public dialog: MdDialog) {}
  
    loadData() {
      this.http.get(url, options)
     .map(response => response.json())
      .subscribe(res => {
        console.log(res['cumulativeplayerstats'].playerstatsentry, 'got player info res!');
        this.cumulativePlayerStatData = res['cumulativeplayerstats'].playerstatsentry;
      });

      this.showData = this.cumulativePlayerStatData;

      //This fills the dataTable with data
      this.dataSource = new MyDataSource(this.showData);

   }
   
   ngOnInit() {
    this.loadData();
   }
  
  //THIS FUNCTION IS CALLED FROM APP.COMPONENT
  //WHEN A TABLE ROW IS CLICKED PASSING IN THAT PLAYERS DATA 
  //TO THE MODAL. THEN MODAL IS CALLED TO OPEN. 
  //HTML FOR MODAL BELOW
  public open(event, data) {
    this.selected = data;
    console.log(data, 'ok you clicked on a table row....');
    this.dialog.open(MyDialog, {
      data: data,
      width: '600px',
    });
  }

}

@Component({
  selector: 'my-dialog',
  template: `<md-dialog-content>
  <md-icon (click)="dialogRef.close()" style="float:right; cursor:pointer;">close</md-icon>
</md-dialog-content>
<md-grid-list cols="3" rowHeight="200px" class="dialog-head">
  <md-grid-tile [colspan]="1">
    <img src="{{ data.player.image }}">
  </md-grid-tile>
  <md-grid-tile [colspan]="2">
    <p>{{ data.player.FirstName + ' ' + data.player.LastName + ' (' + data.team.Name + ' - ' + data.player.Position + ')'}} <span *ngIf="data.player.IsRookie == 'true'" style="background:#2ecc71; color:#fff; padding:1px; border-radius:2px;">Rookie</span>
      <br> Age: {{data.player.age}} Height: {{data.player.Height}} Weight: {{data.player.Weight}}
      <br> Birth City: {{data.player.city +', '+ data.player.country}}
      <br> Number: {{data.player.JerseyNumber}}</p>
  </md-grid-tile>
</md-grid-list>
<md-grid-list cols="3" rowHeight="50px">
  <md-grid-tile [colspan]="1">
    <h1><b>W-L:</b> {{ data.stats.Wins['#text'] +'-'+ data.stats.Losses['#text'] }}</h1>
  </md-grid-tile>
  <md-grid-tile [colspan]="1">
    <h1><b>ERA:</b> {{ data.stats.EarnedRunAvg['#text'] }}</h1>
  </md-grid-tile>
  <md-grid-tile [colspan]="1">
    <h1><b>K's:</b> {{ data.stats.PitcherStrikeouts['#text'] }}</h1>
  </md-grid-tile>
</md-grid-list>`,
})

export class MyDialog {
  constructor(public dialogRef: MdDialogRef < MyDialog > , @Inject(MD_DIALOG_DATA) public data: any) {}
}

export class MyDataSource extends DataSource <Data> {

  constructor(private datas: Data[]) {
    super();
  }

  connect(): Observable <Data[]> {
    return Observable.of(this.data); 
  }

  disconnect() {}

}
//app.compoent.html

<div id="exampleContainer" class="example-container example-container-fixed mat-elevation-z8">
  <md-table #table [dataSource]="dataSource">
    <!-- Rank Column and Name of Player -->
    <ng-container cdkColumnDef="id">
      <md-header-cell *cdkHeaderCellDef>
        Rank 
      </md-header-cell>
      <md-cell *cdkCellDef="let i=index; let data;">
          <b>{{i+1}}. </b>{{ data.player.FirstName + ' ' + data.player.LastName + ' - ' + data.team.Abbreviation}}
      </md-cell>
    </ng-container>
    <!-- Pitches Column -->
    <ng-container cdkColumnDef="pitches">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pitch Count </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.PitchesThrown['#text']}} </md-cell>
    </ng-container>
    <!-- StrikeOuts Column -->
    <ng-container cdkColumnDef="strikeouts">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Strike Outs </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.PitcherStrikeouts['#text']}} </md-cell>
    </ng-container>
    <!-- PitcherWalks Column -->
    <ng-container cdkColumnDef="pitcherWalks">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pitcher Walks </md-header-cell>
      <md-cell *cdkCellDef="let data">
        {{data.stats.PitcherWalks['#text']}}
      </md-cell>
    </ng-container>
    <!-- InningsPitched Column -->
    <ng-container cdkColumnDef="inningsPitched">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Innings Pitched </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.InningsPitched['#text']}}</md-cell>
    </ng-container>
    <!-- pitchesPerInning Column -->
    <ng-container cdkColumnDef="pitchesPerInning">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pitches Per Inning </md-header-cell>
      <md-cell *cdkCellDef="let data">
        {{data.stats.PitchesPerInning['#text']}}
      </md-cell>
    </ng-container>
    <!-- PitcherWildPitches Column -->
    <ng-container cdkColumnDef="pitcherWildPitches">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Wild Pitches </md-header-cell>
      <md-cell *cdkCellDef="let data">{{data.stats.PitcherWildPitches['#text']}}</md-cell>
    </ng-container>
    <!-- PickoffAttempts Column -->
    <ng-container cdkColumnDef="pickoffAttempts">
      <md-header-cell *cdkHeaderCellDef md-sort-header> Pickoff Attempts </md-header-cell>
      <md-cell *cdkCellDef="let data">
        {{data.stats.PickoffAttempts['#text']}}
      </md-cell>
    </ng-container>
    <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
    <md-row (click)="open($event, data)" *cdkRowDef="let data; columns: displayedColumns; let i=index;"></md-row>
  </md-table>
</div>
  • My example shows the older naming conventions for MdDialog which is now called MatDialog. The main difference is the import would look like this import {MatDialogModule} from '@angular/material';

Check the codebase on my GitHub account!