diff --git a/src/material-examples/example-module.ts b/src/material-examples/example-module.ts index 07bda41ad4ae..2111b28e6845 100644 --- a/src/material-examples/example-module.ts +++ b/src/material-examples/example-module.ts @@ -70,6 +70,7 @@ import {PizzaPartyComponent,SnackBarComponentExample} from './snack-bar-componen import {SnackBarOverviewExample} from './snack-bar-overview/snack-bar-overview-example'; import {SortOverviewExample} from './sort-overview/sort-overview-example'; import {TableBasicExample} from './table-basic/table-basic-example'; +import {TableHttpExample} from './table-http/table-http-example'; import {TableFilteringExample} from './table-filtering/table-filtering-example'; import {TableOverviewExample} from './table-overview/table-overview-example'; import {TablePaginationExample} from './table-pagination/table-pagination-example'; @@ -424,6 +425,12 @@ export const EXAMPLE_COMPONENTS = { additionalFiles: null, selectorName: null }, + 'table-http': { + title: 'Table retrieving data through HTTP', + component: TableHttpExample, + additionalFiles: null, + selectorName: null + }, 'table-filtering': { title: 'Table with filtering', component: TableFilteringExample, diff --git a/src/material-examples/table-http/table-http-example.css b/src/material-examples/table-http/table-http-example.css new file mode 100644 index 000000000000..7c989781b575 --- /dev/null +++ b/src/material-examples/table-http/table-http-example.css @@ -0,0 +1,57 @@ +/* Structure */ +.example-container { + display: flex; + flex-direction: column; + max-height: 500px; + min-width: 300px; + position: relative; +} + +.example-header { + min-height: 64px; + display: flex; + align-items: center; + padding-left: 24px; + font-size: 20px; +} + +.example-table { + overflow: auto; + min-height: 300px; +} + +.mat-column-title { + text-overflow: ellipsis; + white-space: nowrap; + flex: 1; + overflow: hidden; +} + +/* Column Widths */ +.mat-column-number, +.mat-column-state { + max-width: 64px; +} + +.mat-column-created { + max-width: 124px; +} + +.example-loading-shade { + position: absolute; + top: 0; + left: 0; + bottom: 56px; + right: 0; + background: rgba(0, 0, 0, 0.15); + z-index: 1; + display: flex; + align-items: center; + justify-content: center; +} + +.example-rate-limit-reached { + color: #980000; + max-width: 360px; + text-align: center; +} \ No newline at end of file diff --git a/src/material-examples/table-http/table-http-example.html b/src/material-examples/table-http/table-http-example.html new file mode 100644 index 000000000000..d9c7ce4a79ce --- /dev/null +++ b/src/material-examples/table-http/table-http-example.html @@ -0,0 +1,46 @@ +
+
+ +
+ GitHub's API rate limit has been reached. It will be reset in one minute. +
+
+ + + + + + + + Number + {{row.number}} + + + + + Title + {{row.title}} + + + + + State + {{row.state}} + + + + + Created + {{row.created.toDateString()}} + + + + + + + +
\ No newline at end of file diff --git a/src/material-examples/table-http/table-http-example.ts b/src/material-examples/table-http/table-http-example.ts new file mode 100644 index 000000000000..a2c9da53161b --- /dev/null +++ b/src/material-examples/table-http/table-http-example.ts @@ -0,0 +1,129 @@ +import {Component, ViewChild} from '@angular/core'; +import {Http, Response} from '@angular/http'; +import {DataSource} from '@angular/cdk'; +import {MdPaginator, MdSort} from '@angular/material'; +import {Observable} from 'rxjs/Observable'; +import 'rxjs/add/operator/first'; +import 'rxjs/add/operator/startWith'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/switchMap'; +import 'rxjs/add/observable/merge'; +import 'rxjs/add/observable/of'; +import 'rxjs/add/observable/interval'; +import 'rxjs/add/operator/map'; + +@Component({ + selector: 'table-http-example', + styleUrls: ['table-http-example.css'], + templateUrl: 'table-http-example.html', +}) +export class TableHttpExample { + displayedColumns = ['created', 'state', 'number', 'title']; + exampleDatabase: ExampleHttpDao | null; + dataSource: ExampleDataSource | null; + + @ViewChild(MdPaginator) paginator: MdPaginator; + @ViewChild(MdSort) sort: MdSort; + + constructor(http: Http) { + this.exampleDatabase = new ExampleHttpDao(http); + } + + ngOnInit() { + this.dataSource = new ExampleDataSource(this.exampleDatabase!, + this.sort, this.paginator); + } +} + +export interface GithubIssue { + number: string; + state: string; + title: string; + created: Date; +} + +/** An example database that the data source uses to retrieve data for the table. */ +export class ExampleHttpDao { + constructor(private http: Http) {} + + getRepoIssues(sort: string, order: string, page: number): Observable { + const href = 'https://api.github.com/search/issues'; + const requestUrl = + `${href}?q=repo:angular/material2&sort=${sort}&order=${order}&page=${page + 1}`; + return this.http.get(requestUrl); + } +} + +/** + * 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, ExampleHttpDao. 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 { + // The number of issues returned by github matching the query. + resultsLength: number = 0; + isLoadingResults: boolean; + isRateLimitReached: boolean; + + constructor(private _exampleDatabase: ExampleHttpDao, + private _sort: MdSort, + private _paginator: MdPaginator) { + super(); + } + + /** Connect function called by the table to retrieve one stream containing the data to render. */ + connect(): Observable { + const displayDataChanges = [ + this._sort.mdSortChange, + this._paginator.page, + ]; + + // If the user changes the sort order, reset back to the first page. + this._sort.mdSortChange.subscribe(() => { + this._paginator.pageIndex = 0; + }); + + return Observable.merge(...displayDataChanges) + .startWith(null) + .switchMap(() => { + this.isLoadingResults = true; + return this._exampleDatabase.getRepoIssues( + this._sort.active, this._sort.direction, this._paginator.pageIndex); + }) + .catch(() => { + // Catch if the GitHub API has reached its rate limit. Return empty result. + this.isRateLimitReached = true; + return Observable.of(null); + }) + .map(result => { + // Flip flag to show that loading has finished. + this.isLoadingResults = false; + return result; + }) + .map(result => { + if (!result) { return []; } + + this.isRateLimitReached = false; + this.resultsLength = result.json().total_count; + + return this.readGithubResult(result); + }); + + + } + + disconnect() {} + + private readGithubResult(result: Response): GithubIssue[] { + return result.json().items.map(issue => { + return { + number: issue.number, + created: new Date(issue.created_at), + state: issue.state, + title: issue.title, + }; + }); + } +}