title: Mat-table Sorting Demo not Working
body: <p>I am trying to get the <code>mat-table</code> sorting to work locally, and while I can get the data to show up as expected, clicking on the header row does not do the sorting as it does on online examples (nothing happens at all).
  I am trying to get this demo working locally:
  <a href="https://material.angular.io/components/sort/overview" rel="noreferrer">https://material.angular.io/components/sort/overview</a>
  <a href="https://plnkr.co/edit/XF5VxOSEBxMTd9Yb3ZLA?p=preview" rel="noreferrer">https://plnkr.co/edit/XF5VxOSEBxMTd9Yb3ZLA?p=preview</a></p>
  
  <p>I have generated a new project with Angular CLI, then followed these steps:
  <a href="https://material.angular.io/guide/getting-started" rel="noreferrer">https://material.angular.io/guide/getting-started</a></p>
  
  <p>Here are my local files:</p>
  
  <p><strong>app.module.ts</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import { BrowserModule } from '@angular/platform-browser';
  import { NgModule } from '@angular/core';
  import { MatSort, MatTableModule } from '@angular/material';
  
  import { AppComponent } from './app.component';
  import { TableSortingExample } from './table-sorting-example';
  
  @NgModule({
    declarations: [
      AppComponent,
      TableSortingExample,
      MatSort
    ],
    imports: [
      BrowserModule,
      MatTableModule
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }
  </code></pre>
  
  <p><strong>app.component.ts</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import { Component } from '@angular/core';
  
  @Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
  })
  export class AppComponent {
    title = 'app';
  }
  </code></pre>
  
  <p><strong>app.component.html</strong></p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;div style="text-align:center"&gt;
    &lt;h1&gt;
      Welcome to {{title}}!
    &lt;/h1&gt;
    &lt;table-sorting-example&gt;&lt;/table-sorting-example&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>table-sorting-example.html</strong></p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;div class="example-container mat-elevation-z8"&gt;
    &lt;mat-table #table [dataSource]="dataSource" matSort&gt;
  
      &lt;!--- Note that these columns can be defined in any order.
            The actual rendered columns are set as a property on the row definition" --&gt;
  
      &lt;!-- ID Column --&gt;
      &lt;ng-container matColumnDef="userId"&gt;
        &lt;mat-header-cell *matHeaderCellDef mat-sort-header&gt; ID &lt;/mat-header-cell&gt;
        &lt;mat-cell *matCellDef="let row"&gt; {{row.id}} &lt;/mat-cell&gt;
      &lt;/ng-container&gt;
  
      &lt;!-- Progress Column --&gt;
      &lt;ng-container matColumnDef="progress"&gt;
        &lt;mat-header-cell *matHeaderCellDef mat-sort-header&gt; Progress &lt;/mat-header-cell&gt;
        &lt;mat-cell *matCellDef="let row"&gt; {{row.progress}}% &lt;/mat-cell&gt;
      &lt;/ng-container&gt;
  
      &lt;!-- Name Column --&gt;
      &lt;ng-container matColumnDef="userName"&gt;
        &lt;mat-header-cell *matHeaderCellDef mat-sort-header&gt; Name &lt;/mat-header-cell&gt;
        &lt;mat-cell *matCellDef="let row"&gt; {{row.name}} &lt;/mat-cell&gt;
      &lt;/ng-container&gt;
  
      &lt;!-- Color Column --&gt;
      &lt;ng-container matColumnDef="color"&gt;
        &lt;mat-header-cell *matHeaderCellDef mat-sort-header&gt; Color &lt;/mat-header-cell&gt;
        &lt;mat-cell *matCellDef="let row" [style.color]="row.color"&gt; {{row.color}} &lt;/mat-cell&gt;
      &lt;/ng-container&gt;
  
      &lt;mat-header-row *matHeaderRowDef="displayedColumns"&gt;&lt;/mat-header-row&gt;
      &lt;mat-row *matRowDef="let row; columns: displayedColumns;"&gt;&lt;/mat-row&gt;
    &lt;/mat-table&gt;
  &lt;/div&gt;
  
  
  &lt;!-- Copyright 2017 Google Inc. All Rights Reserved.
      Use of this source code is governed by an MIT-style license that
      can be found in the LICENSE file at http://angular.io/license --&gt;
  </code></pre>
  
  <p><strong>table-sorting-example.ts</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>import {Component, ViewChild} from '@angular/core';
  import {DataSource} from '@angular/cdk/collections';
  import {MatSort} from '@angular/material';
  import {BehaviorSubject} from 'rxjs/BehaviorSubject';
  import {Observable} from 'rxjs/Observable';
  import 'rxjs/add/operator/startWith';
  import 'rxjs/add/observable/merge';
  import 'rxjs/add/operator/map';
  
  /**
   * @title Table with sorting
   */
  @Component({
    selector: 'table-sorting-example',
    styleUrls: ['table-sorting-example.css'],
    templateUrl: 'table-sorting-example.html',
  })
  export class TableSortingExample {
    displayedColumns = ['userId', 'userName', 'progress', 'color'];
    exampleDatabase = new ExampleDatabase();
    dataSource: ExampleDataSource | null;
  
    @ViewChild(MatSort) sort: MatSort;
  
    ngOnInit() {
      this.dataSource = new ExampleDataSource(this.exampleDatabase, this.sort);
    }
  }
  
  /** Constants used to fill up our data base. */
  const COLORS = ['maroon', 'red', 'orange', 'yellow', 'olive', 'green', 'purple',
    'fuchsia', 'lime', 'teal', 'aqua', 'blue', 'navy', 'black', 'gray'];
  const NAMES = ['Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia', 'Jack',
    'Charlotte', 'Theodore', 'Isla', 'Oliver', 'Isabella', 'Jasper',
    'Cora', 'Levi', 'Violet', 'Arthur', 'Mia', 'Thomas', 'Elizabeth'];
  
  export interface UserData {
    id: string;
    name: string;
    progress: string;
    color: string;
  }
  
  /** An example database that the data source uses to retrieve data for the table. */
  export class ExampleDatabase {
    /** Stream that emits whenever the data has been modified. */
    dataChange: BehaviorSubject&lt;UserData[]&gt; = new BehaviorSubject&lt;UserData[]&gt;([]);
    get data(): UserData[] { return this.dataChange.value; }
  
    constructor() {
      // Fill up the database with 100 users.
      for (let i = 0; i &lt; 100; i++) { this.addUser(); }
    }
  
    /** Adds a new user to the database. */
    addUser() {
      const copiedData = this.data.slice();
      copiedData.push(this.createNewUser());
      this.dataChange.next(copiedData);
    }
  
    /** Builds and returns a new User. */
    private createNewUser() {
      const name =
        NAMES[Math.round(Math.random() * (NAMES.length - 1))] + ' ' +
        NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0) + '.';
  
      return {
        id: (this.data.length + 1).toString(),
        name: name,
        progress: Math.round(Math.random() * 100).toString(),
        color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
      };
    }
  }
  
  /**
   * Data source to provide what data should be rendered in the table. Note that the data source
   * can retrieve its data in any way. In this case, the data source is provided a reference
   * to a common data base, ExampleDatabase. It is not the data source's responsibility to manage
   * the underlying data. Instead, it only needs to take the data and send the table exactly what
   * should be rendered.
   */
  export class ExampleDataSource extends DataSource&lt;any&gt; {
    constructor(private _exampleDatabase: ExampleDatabase, private _sort: MatSort) {
      super();
    }
  
    /** Connect function called by the table to retrieve one stream containing the data to render. */
    connect(): Observable&lt;UserData[]&gt; {
      const displayDataChanges = [
        this._exampleDatabase.dataChange,
        this._sort.sortChange,
      ];
  
      return Observable.merge(...displayDataChanges).map(() =&gt; {
        return this.getSortedData();
      });
    }
  
    disconnect() {}
  
    /** Returns a sorted copy of the database data. */
    getSortedData(): UserData[] {
      const data = this._exampleDatabase.data.slice();
      if (!this._sort.active || this._sort.direction == '') { return data; }
  
      return data.sort((a, b) =&gt; {
        let propertyA: number|string = '';
        let propertyB: number|string = '';
  
        switch (this._sort.active) {
          case 'userId': [propertyA, propertyB] = [a.id, b.id]; break;
          case 'userName': [propertyA, propertyB] = [a.name, b.name]; break;
          case 'progress': [propertyA, propertyB] = [a.progress, b.progress]; break;
          case 'color': [propertyA, propertyB] = [a.color, b.color]; break;
        }
  
        let valueA = isNaN(+propertyA) ? propertyA : +propertyA;
        let valueB = isNaN(+propertyB) ? propertyB : +propertyB;
  
        return (valueA &lt; valueB ? -1 : 1) * (this._sort.direction == 'asc' ? 1 : -1);
      });
    }
  }
  
  
  /**  Copyright 2017 Google Inc. All Rights Reserved.
   Use of this source code is governed by an MIT-style license that
   can be found in the LICENSE file at http://angular.io/license */
  </code></pre>
  
  <p>Does anyone have an idea of why it would show up like the online table but lack the sorting functionality?</p>