簡體   English   中英

用api調用Angular實現Material Table

[英]Implementing Material Table with api call Angular

我一直在使用Angular 2開發應用程序,但作為新開發人員,這樣做確實很費力。 到目前為止,我已經做了很多工作,但是我確實需要一些幫助。 我包括一個plunkr,我將以此為參考來獲取具有分頁,過濾和排序的Material Table,但此示例以及material.angular.io上的所有其他示例均顯示了一個示例數據庫本質上是在組件類中硬編碼/生成的。 我有一個調用SQL查詢api的服務,我想以此為例填充表,但是到目前為止,我的嘗試都是慘痛的失敗,我認為我在此過程中不堪重負。

根據要求,我可以發布組件代碼,但是我擔心自己已​​刪除/修改了它,超出了任何使用的范圍。 但在此之前,下面是我想要實現的plunkr,以及我想用來代替plunkr的數據庫和數據源填充數據表的服務類。

如果您可以提供幫助,請告訴我,您將為我省去很多麻煩。

https://plnkr.co/edit/EU3BBlViWpPf2NJW4PXx?p=preview

我的服務

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代碼的表中刪除了與選擇有關的所有內容,剩下的就是我當前所在的位置。 如果這最終帶來的阻礙多於幫助,我感到非常抱歉。

哦,這可能會有所幫助,服務器端的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'"

柱塞示例

如果我們不使用ngIf那么我們就不需要ChangeDetectorRef

柱塞示例

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM