neves
neves

Reputation: 39373

Angular: how to connect a Service to a Material RankTable?

I'm learning Angular and trying to grasp the concepts. I'm having difficulty doing something that should be simple.

I want to connect a Material Table to a service that downloads some data.

I created my service that downloads some simple data from a website. I created the Data Table using the command line. Now I must change the data source for my service.

Here is the generated file rank-table-datasource.ts:

import { DataSource } from '@angular/cdk/collections';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge } from 'rxjs';

// TODO: Replace this with your own data model type
export interface RankTableItem {
  name: string;
  id: number;
}

// TODO: replace this with real data from your application
const EXAMPLE_DATA: RankTableItem[] = [
  {id: 1, name: 'Hydrogen'},
  {id: 2, name: 'Helium'},
  {id: 3, name: 'Lithium'},
  {id: 4, name: 'Beryllium'},
  {id: 5, name: 'Boron'},
  {id: 6, name: 'Carbon'},
  {id: 7, name: 'Nitrogen'},
  {id: 8, name: 'Oxygen'},
  {id: 9, name: 'Fluorine'},
  {id: 10, name: 'Neon'},
  {id: 11, name: 'Sodium'},
  {id: 12, name: 'Magnesium'},
  {id: 13, name: 'Aluminum'},
  {id: 14, name: 'Silicon'},
  {id: 15, name: 'Phosphorus'},
  {id: 16, name: 'Sulfur'},
  {id: 17, name: 'Chlorine'},
  {id: 18, name: 'Argon'},
  {id: 19, name: 'Potassium'},
  {id: 20, name: 'Calcium'},
];

/**
 * Data source for the RankTable view. This class should
 * encapsulate all logic for fetching and manipulating the displayed data
 * (including sorting, pagination, and filtering).
 */
export class RankTableDataSource extends DataSource<RankTableItem> {
  data: RankTableItem[] = EXAMPLE_DATA;
  paginator: MatPaginator;
  sort: MatSort;

  constructor() {
    super();
  }

  /**
   * Connect this data source to the table. The table will only update when
   * the returned stream emits new items.
   * @returns A stream of the items to be rendered.
   */
  connect(): Observable<RankTableItem[]> {
    // Combine everything that affects the rendered data into one update
    // stream for the data-table to consume.
    const dataMutations = [
      observableOf(this.data),
      this.paginator.page,
      this.sort.sortChange
    ];

    return merge(...dataMutations).pipe(map(() => {
      return this.getPagedData(this.getSortedData([...this.data]));
    }));
  }

  /**
   *  Called when the table is being destroyed. Use this function, to clean up
   * any open connections or free any held resources that were set up during connect.
   */
  disconnect() {}

  /**
   * Paginate the data (client-side). If you're using server-side pagination,
   * this would be replaced by requesting the appropriate data from the server.
   */
  private getPagedData(data: RankTableItem[]) {
    const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
    return data.splice(startIndex, this.paginator.pageSize);
  }

  /**
   * Sort the data (client-side). If you're using server-side sorting,
   * this would be replaced by requesting the appropriate data from the server.
   */
  private getSortedData(data: RankTableItem[]) {
    if (!this.sort.active || this.sort.direction === '') {
      return data;
    }

    return data.sort((a, b) => {
      const isAsc = this.sort.direction === 'asc';
      switch (this.sort.active) {
        case 'name': return compare(a.name, b.name, isAsc);
        case 'id': return compare(+a.id, +b.id, isAsc);
        default: return 0;
      }
    });
  }
}

/** Simple sort comparator for example ID/Name columns (for client-side sorting). */
function compare(a: string | number, b: string | number, isAsc: boolean) {
  return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}

I imported my service and my interface:

import { EscolaService } from '../escola.service'
import { Escola } from '../escola';

My Interface also has just an id and a name, like the original.

Defined an alias for my type. Don't know if this is the correct way:

export type RankTableItem = Escola;

I should now redefine the connect() method:

connect(): Observable<RankTableItem[]> {

but I don't know how to do it.

The rank-table-component.html tries to use some dataSource methods:

  <mat-paginator #paginator
      [length]="dataSource?.data.length"
      [pageIndex]="0"
      [pageSize]="50"
      [pageSizeOptions]="[25, 50, 100, 250]">

How should I use this connect method and the Observer generated by my Service?

Upvotes: 0

Views: 544

Answers (1)

er-sho
er-sho

Reputation: 9771

You can use your own datasource like below

a. This is your custom datasource that you defined.

export class RankTableDataSource extends DataSource<RankTableItem> {

  //Your rest of the code with connect() and disconnect() methods.

}

b. Then you can consume the above data source in your component like

export class YourComponent implements OnInit, AfterViewInit {

    //Take your data source into data bound property
    dataSource: RankTableDataSource;

    constructor(  ) {}


    //Initialize your data source in onInit method
    ngOnInit() {
        this.dataSource = new RankTableDataSource();
    }    
}

c. Then use this dataSource into your template.

The connect() and disconnect() methods automatically invoked by mat-table data source. You don't need to manually called those methods into your own code if you used custom data source.

Upvotes: 1

Related Questions