2017-11-10 115 views
0

这是使用示例数据库来填充它的材料数据表。它还包含排序,分页和过滤。我已经设法使用我的Firestore数据(来自服务)填充具有排序和分页功能的表格。不过,我无法获得过滤工作,我无法弄清楚为什么。我知道这是一个很长的镜头,但我希望有人能告诉我如何实现一个Firestore数据库来代替下面的示例数据库。使用Firestore进行过滤的角度材料数据表

example.ts:

import {Component, ElementRef, ViewChild} from '@angular/core'; 
import {DataSource} from '@angular/cdk/collections'; 
import {MatPaginator, MatSort} from '@angular/material'; 
import {SelectionModel} from '@angular/cdk/collections'; 
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'; 

/** 
* @title Feature-rich data table 
*/ 
@Component({ 
    selector: 'table-overview-example', 
    styleUrls: ['table-overview-example.css'], 
    templateUrl: 'table-overview-example.html', 
}) 
export class TableOverviewExample { 
    displayedColumns = ['select', 'userId', 'userName', 'progress', 'color']; 
    exampleDatabase = new ExampleDatabase(); 
    selection = new SelectionModel<string>(true, []); 
    dataSource: ExampleDataSource | null; 

    @ViewChild(MatPaginator) paginator: MatPaginator; 
    @ViewChild(MatSort) sort: MatSort; 
    @ViewChild('filter') filter: ElementRef; 

    ngOnInit() { 
    this.dataSource = new ExampleDataSource(this.exampleDatabase, 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; 
     }); 
    } 

    isAllSelected(): boolean { 
    if (!this.dataSource) { return false; } 
    if (this.selection.isEmpty()) { return false; } 

    if (this.filter.nativeElement.value) { 
     return this.selection.selected.length == this.dataSource.renderedData.length; 
    } else { 
     return this.selection.selected.length == this.exampleDatabase.data.length; 
    } 
    } 

    masterToggle() { 
    if (!this.dataSource) { return; } 

    if (this.isAllSelected()) { 
     this.selection.clear(); 
    } else if (this.filter.nativeElement.value) { 
     this.dataSource.renderedData.forEach(data => this.selection.select(data.id)); 
    } else { 
     this.exampleDatabase.data.forEach(data => this.selection.select(data.id)); 
    } 
    } 
} 

/** 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<UserData[]> = new BehaviorSubject<UserData[]>([]); 
    get data(): UserData[] { return this.dataChange.value; } 

    constructor() { 
    // Fill up the database with 100 users. 
    for (let i = 0; i < 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<any> { 
    _filterChange = new BehaviorSubject(''); 
    get filter(): string { return this._filterChange.value; } 
    set filter(filter: string) { this._filterChange.next(filter); } 

    filteredData: UserData[] = []; 
    renderedData: UserData[] = []; 

    constructor(private _exampleDatabase: ExampleDatabase, 
       private _paginator: MatPaginator, 
       private _sort: MatSort) { 
    super(); 

    // Reset to the first page when the user changes the filter. 
    this._filterChange.subscribe(() => this._paginator.pageIndex = 0); 
    } 

    /** Connect function called by the table to retrieve one stream containing the data to render. */ 
    connect(): Observable<UserData[]> { 
    // Listen for any changes in the base data, sorting, filtering, or pagination 
    const displayDataChanges = [ 
     this._exampleDatabase.dataChange, 
     this._sort.sortChange, 
     this._filterChange, 
     this._paginator.page, 
    ]; 

    return Observable.merge(...displayDataChanges).map(() => { 
     // Filter data 
     this.filteredData = this._exampleDatabase.data.slice().filter((item: UserData) => { 
     let searchStr = (item.name + item.color).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: UserData[]): UserData[] { 
    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 '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 < valueB ? -1 : 1) * (this._sort.direction == 'asc' ? 1 : -1); 
    }); 
    } 
} 

example.html的:

<div class="example-header" [style.display]="selection.isEmpty() ? '' : 'none'"> 
    <mat-form-field floatPlaceholder="never"> 
    <input matInput #filter placeholder="Filter users"> 
    </mat-form-field> 
</div> 
<div class="example-header example-selection-header" 
    *ngIf="!selection.isEmpty()"> 
    {{selection.selected.length}} 
    {{selection.selected.length == 1 ? 'user' : 'users'}} 
    selected 
</div> 

<div class="example-container mat-elevation-z8"> 

    <mat-table #table [dataSource]="dataSource" matSort> 

    <!--- Note that these columns can be defined in any order. 
      The actual rendered columns are set as a property on the row definition" --> 

    <!-- Checkbox Column --> 
    <ng-container matColumnDef="select"> 
     <mat-header-cell *matHeaderCellDef> 
     <mat-checkbox (change)="$event ? masterToggle() : null" 
        [checked]="isAllSelected()" 
        [indeterminate]="selection.hasValue() && !isAllSelected()"> 
     </mat-checkbox> 
     </mat-header-cell> 
     <mat-cell *matCellDef="let row"> 
     <mat-checkbox (click)="$event.stopPropagation()" 
        (change)="$event ? selection.toggle(row.id) : null" 
        [checked]="selection.isSelected(row.id)"> 
     </mat-checkbox> 
     </mat-cell> 
    </ng-container> 

    <!-- ID Column --> 
    <ng-container matColumnDef="userId"> 
     <mat-header-cell *matHeaderCellDef mat-sort-header> ID </mat-header-cell> 
     <mat-cell *matCellDef="let row"> {{row.id}} </mat-cell> 
    </ng-container> 

    <!-- Progress Column --> 
    <ng-container matColumnDef="progress"> 
     <mat-header-cell *matHeaderCellDef mat-sort-header> Progress </mat-header-cell> 
     <mat-cell *matCellDef="let row"> {{row.progress}}% </mat-cell> 
    </ng-container> 

    <!-- Name Column --> 
    <ng-container matColumnDef="userName"> 
     <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> 
     <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell> 
    </ng-container> 

    <!-- Color Column --> 
    <ng-container matColumnDef="color"> 
     <mat-header-cell *matHeaderCellDef mat-sort-header> Color </mat-header-cell> 
     <mat-cell *matCellDef="let row" [style.color]="row.color"> {{row.color}} </mat-cell> 
    </ng-container> 

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> 
    <mat-row *matRowDef="let row; columns: displayedColumns;" 
      [class.example-selected-row]="selection.isSelected(row.id)" 
      (click)="selection.toggle(row.id)"> 
    </mat-row> 
    </mat-table> 

    <div class="example-no-results" 
     [style.display]="dataSource.renderedData.length == 0 ? '' : 'none'"> 
    No users found matching filter. 
    </div> 

    <mat-paginator #paginator 
       [length]="dataSource.filteredData.length" 
       [pageIndex]="0" 
       [pageSize]="25" 
       [pageSizeOptions]="[5, 10, 25, 100]"> 
    </mat-paginator> 
</div> 

回答

0

尝试重构和放置在数据的排序过滤器,这是我得到了过滤,分页和排序工作。在重构其余代码以使用重构数据源类之前,您将收到错误:

export class ExampleDataSource extends DataSource<any> { 

      _filterChange = new BehaviorSubject(''); 
      get filter(): string { return this._filterChange.value; } 
      set filter(filter: string) { this._filterChange.next(filter); } 

      renderedData: UserData[] = []; 

      constructor(private _exampleDatabase: ExampleDatabase, 
         private _paginator: MatPaginator, 
         private _sort: MatSort) { 
       super(); 
      } 

      connect(): Observable<Data[]> { 
       const displayDataChanges = [ 
        this._exampleDatabase.dataChange, 
        this._paginator.page, 
        this._sort.sortChange, 
        this._filterChange 
       ]; 

       return Observable.merge(...displayDataChanges).map(() => { 
        const startIndex = this._paginator.pageIndex * this._paginator.pageSize; 
        this.renderedData= this.sortData(); 
        return this.renderedData.splice(startIndex, this._paginator.pageSize); 
       }); 
      } 

      disconnect() {} 

      sortData(): Data[] { 
       const data = this._exampleDatabase.data.slice().filter((item: Data) => {   
         let searchStr = (item.name + item.color).toLowerCase();    
         return searchStr.indexOf(this.filter.toLowerCase()) != -1; 
       }); 

       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 '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 < valueB ? -1 : 1) * (this._sort.direction == 'asc' ? 1 : -1); 
       }); 
      } 
}