使用API​​调用Angular实现材料表

我一直在开发一个Angular 2的应用程序,无可否认的是,作为一个新的开发者正在努力。 到目前为止我已经pipe理了很多,但是我确实需要一些帮助。 我包括一个plunkr,我用它作为引用来获得一个材料表的分页,过滤和sorting,但这个例子,以及所有其他的例子在material.angular.io显示一个数据库的例子本质上硬编码/在组件类中生成。 我有一个服务,调用一个SQL查询的API,我想在这个例子填充表中,但我迄今为止的尝试已经是可悲的失败,我想我已经在这个过程中压倒了我自己。

通过请求我可以发布我的组件代码,但我担心,我已经超出任何使用点去除/修改它。 但在此之前,下面是我想要实现的plunkr,以及我希望用来填充数据表以代替plunkr的数据库和数据源的服务类。

请让我知道,如果你能帮助,你会为我节省一大笔头痛。

我的服务

import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; @Injectable() export class RcgqueueService { constructor(private http: Http) { } populateRCGQueue() { return this.http.get('/api/rcgqueue').map(res => res.json()); } } 

而我目前的组件代码的可怜尝试

 import { Component, ElementRef, ViewChild, OnInit, forwardRef } from '@angular/core'; import { DataSource, SelectionModel } from '@angular/cdk/collections'; import { MatPaginator, MatSort, MatTable } 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/observable/fromEvent'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/distinctUntilChanged'; import 'rxjs/add/operator/debounceTime'; import { RcgqueueService } from './rcgqueue.service'; @Component({ selector: 'app-rcgqueue', templateUrl: './rcgqueue.component.html', styleUrls: ['./rcgqueue.component.css'] }) export class RcgqueueComponent implements OnInit { isDataAvailable = false; displayedColumns = ['changeId', 'changeTitle', 'dateSubmitted', 'changeSponsor', 'changeDescription']; dataChange: BehaviorSubject<ChangeData[]> = new BehaviorSubject<ChangeData[]>([]); get data(): ChangeData[] { return this.dataChange.value; } dataSource: ExampleDataSource | null; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(forwardRef(() => MatSort)) sort: MatSort; @ViewChild('filter') filter: ElementRef; constructor(private rcgservice: RcgqueueService) { } populateRCGQueue() { this.rcgservice.populateRCGQueue().subscribe(rcgitems => { this.dataChange = rcgitems; this.isDataAvailable = true; }) } ngOnInit() { this.populateRCGQueue(); this.dataSource = new ExampleDataSource(this, this.paginator, this.sort); Observable.fromEvent(this.filter.nativeElement, 'keyup') .debounceTime(150) .distinctUntilChanged() .subscribe(() => { if (!this.dataSource) { return; } this.dataSource.filter = this.filter.nativeElement.value; }); } } export interface ChangeData { ChangeId: string; ChangeTitle: string; DateSubmitted: string; ChangeSponsor: string; ChangeDescription: string; } /** * 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<any> { _filterChange = new BehaviorSubject(''); get filter(): string { return this._filterChange.value; } set filter(filter: string) { this._filterChange.next(filter); } dataChange: BehaviorSubject<ChangeData[]> = new BehaviorSubject<ChangeData[]>([]); get data(): ChangeData[] { return this.dataChange.value; } filteredData: ChangeData[] = []; renderedData: ChangeData[] = []; constructor(private rcgcomponent: RcgqueueComponent, private _paginator: MatPaginator, private _sort: MatSort) { super(); this._filterChange.subscribe(() => this._paginator.pageIndex = 0); } /** Connect function called by the table to retrieve one stream containing the data to render. */ connect(): Observable<ChangeData[]> { // Listen for any changes in the base data, sorting, filtering, or pagination const displayDataChanges = [ this.rcgcomponent.dataChange, this._sort.sortChange, this._filterChange, this._paginator.page, ]; return Observable.merge(...displayDataChanges).map(() => { // Filter data this.filteredData = this.rcgcomponent.data.slice().filter((item: ChangeData) => { const searchStr = (item.ChangeDescription + item.ChangeSponsor).toLowerCase(); return searchStr.indexOf(this.filter.toLowerCase()) !== -1; }); // Sort filtered data const sortedData = this.sortData(this.filteredData.slice()); // Grab the page's slice of the filtered sorted data. const startIndex = this._paginator.pageIndex * this._paginator.pageSize; this.renderedData = sortedData.splice(startIndex, this._paginator.pageSize); return this.renderedData; }); } disconnect() { } /** Returns a sorted copy of the database data. */ sortData(data: ChangeData[]): ChangeData[] { if (!this._sort.active || this._sort.direction === '') { return data; } return data.sort((a, b) => { let propertyA: number | string = ''; let propertyB: number | string = ''; switch (this._sort.active) { case 'changeId': [propertyA, propertyB] = [a.ChangeId, b.ChangeId]; break; case 'changeTitle': [propertyA, propertyB] = [a.ChangeTitle, b.ChangeTitle]; break; case 'dateSubmitted': [propertyA, propertyB] = [a.DateSubmitted, b.DateSubmitted]; break; case 'changeSponsor': [propertyA, propertyB] = [a.ChangeSponsor, b.ChangeSponsor]; break; case 'changeDescription': [propertyA, propertyB] = [a.ChangeDescription, b.ChangeDescription]; break; } const valueA = isNaN(+propertyA) ? propertyA : +propertyA; const valueB = isNaN(+propertyB) ? propertyB : +propertyB; return (valueA < valueB ? -1 : 1) * (this._sort.direction === 'asc' ? 1 : -1); }); } } 

我已经删除了从plunkr代码中select表格所做的任何事情,这里剩下的就是我目前的位置。 我很抱歉,如果这最终结束了更多的阻碍,而不是有益的。

哦,这可能是有益的,我的api.js在服务器端与我正在使用的查询。 (到目前为止唯一的一个)

 const express = require('express'); const async = require('async'); const jwt = require('jsonwebtoken'); const shape = require('shape-json'); const router = express.Router(); var sql = require('mssql/msnodesqlv8'); var config = { driver: 'msnodesqlv8', connectionString: 'Driver=SQL Server Native Client 11.0;Server=localhost;Database=Change;Trusted_Connection=yes;', } var conn = new sql.ConnectionPool(config); conn.connect().then(function() { log("Change Governance Database Connection opened"); }).catch(function (err) { console.error(new Date() + " - Issue connecting to the MS SQL database.", err); }); router.get('/', (req, res) => { res.send('api works'); }); router.get('/rcgqueue', (req, res) => { new sql.Request(conn) .query('SELECT ChangeId, ChangeTitle, DateSubmitted, ChangeSponsor, ChangeDescription FROM dbo.ChangeEvaluationForm;') .then(function(recordset) { log("Successful query request for RCG Records."); res.send(recordset.recordset); }).catch(function(err) { log(err); res.send("Issue querying database!"); }); }); /********************************/ /* Functions */ /********************************/ // Log lines with date/time for server function log(msg) { console.log(new Date() + " - " + msg); }; module.exports = router; 

编辑:添加模板和错误。

模板

 <!-- Issues https://github.com/angular/angular/issues/16614 https://github.com/angular/angular/issues/17572 --> <div *ngIf="isDataAvailable"> <div class="example-container mat-elevation-z8"> <div class="example-header"> <md-input-container floatPlaceholder="never"> <input mdInput #filter placeholder="Filter"> </md-input-container> </div> <md-table #table [dataSource]="dataSource" mdSort> <!--- Note that these columns can be defined in any order. The actual rendered columns are set as a property on the row definition" --> <!-- ChangeId Column --> <ng-container cdkColumnDef="changeId"> <md-header-cell *cdkHeaderCellDef md-sort-header> ChangeId </md-header-cell> <md-cell *cdkCellDef="let row"> {{row.ChangeId}} </md-cell> </ng-container> <!-- ChangeTitle Column --> <ng-container cdkColumnDef="changeTitle"> <md-header-cell *cdkHeaderCellDef md-sort-header> Change Title </md-header-cell> <md-cell *cdkCellDef="let row"> {{row.ChangeTitle}}% </md-cell> </ng-container> <!-- DateSubmitted --> <ng-container cdkColumnDef="dateSubmitted"> <md-header-cell *cdkHeaderCellDef md-sort-header> Date Submitted </md-header-cell> <md-cell *cdkCellDef="let row"> {{row.DateSubmitted}} </md-cell> </ng-container> <!-- ChangeSponsor --> <ng-container cdkColumnDef="changeSponsor"> <md-header-cell *cdkHeaderCellDef md-sort-header> Change Sponsor </md-header-cell> <md-cell *cdkCellDef="let row"> {{row.ChangeSponsor}} </md-cell> </ng-container> <!-- ChangeDescription --> <ng-container cdkColumnDef="changeDescription"> <md-header-cell *cdkHeaderCellDef md-sort-header> Change Description </md-header-cell> <md-cell *cdkCellDef="let row"> {{row.ChangeDescription}} </md-cell> </ng-container> <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row> <md-row *cdkRowDef="let row; columns: displayedColumns;"> </md-row> </md-table> <div class="example-no-results" [style.display]="dataSource.renderedData.length == 0 ? '' : 'none'"> No changes found matching filter. </div> <md-paginator #paginator [length]="dataSource.filteredData.length" [pageIndex]="0" [pageSize]="25" [pageSizeOptions]="[5, 10, 25, 100]"> </md-paginator> </div> </div> 

最后是我的错误截图

在这里输入图像描述

你得到的原因

无法设置属性pageIndex的undefined

是你在*ngIf包装表格,当你将@ViewChild传递给DataSource类时,它们还没有被初始化。

获取数据后,我通过调用初始化来解决它:

 this.rcgservice.populateRCGQueue().subscribe(rcgitems => { this.dataChange.next(rcgitems); this.isDataAvailable = true; this.cdRef.detectChanges(); // make sure that all ViewChilds were initialized this.initSource(); 

另一个错误是您将数据分配给BehaviourSubject

 this.rcgservice.populateRCGQueue().subscribe(rcgitems => { this.dataChange = rcgitems; 

它应该是:

 this.dataChange.next(rcgitems); 

我还为您的模板添加了一些安全的导航运算符:

 [length]="dataSource?.filteredData.length" 

 [style.display]="dataSource?.renderedData.length == 0 ? '' : 'none'" 

Plunker例子

如果我们不使用ngIf那么我们不需要ngIf

Plunker例子

Interesting Posts