Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material 2 Data Table Setup As Master - Detail Views?

MD Data Table doesn't come with a master - detail setup. At the time of this post AM2 Data Table has been out for only 3 weeks. There have been a few questions around the Web regarding how to setup the Data Table for master - detail uses. I struggled with it for a while until I figured it out.

Some posters on various sites such as the Data Table's GitHub site would like to be able to click on a row and the rows below slide down to reveal a little data. The Data Table doesn't natively do that and won't for a while.

However, for viewing large amounts of data or editing then buttons and separate views are good. So how to implement this?

like image 879
Preston Avatar asked Oct 29 '22 04:10

Preston


1 Answers

This component brings in all the members of the database, in this case Firebase using AngularFire 2, from a service component. First you must bring in the database key as I did in the last column in the html below. Then I hide it with display: none css. Last is to put the row.$key property into the click param to pass the key string into your code. Simple. For newbies I've included the rest of my code so you don't have to spend hours trying to figure out what is going on. It all just works! Go build cool stuff!

all-members.component.ts

<md-table #table [dataSource]="dataSource">

  <!-- First Name Column -->
  <ng-container cdkColumnDef="firstName">
    <md-header-cell *cdkHeaderCellDef> Name </md-header-cell>
    <md-cell *cdkCellDef="let row"> {{row.firstName}} </md-cell>
  </ng-container>

  <!-- Las Name Column -->
  <ng-container cdkColumnDef="lastName">
    <md-header-cell *cdkHeaderCellDef> Name </md-header-cell>
    <md-cell *cdkCellDef="let row">  {{row.lastName}} </md-cell>
  </ng-container>

  <!-- Title Column -->
  <ng-container cdkColumnDef="mainSkillTitle">
    <md-header-cell *cdkHeaderCellDef> Title </md-header-cell>
    <md-cell *cdkCellDef="let row"> {{row.mainSkillTitle}} </md-cell>
  </ng-container>

  <!-- Main Skills Column -->
  <ng-container cdkColumnDef="mainSkills">
    <md-header-cell *cdkHeaderCellDef> Main Skills </md-header-cell>
    <md-cell *cdkCellDef="let row"> {{row.mainSkills}} </md-cell>
  </ng-container>

  <!-- Delete Buttons Column -->
  <ng-container cdkColumnDef="delete">
    <md-header-cell *cdkHeaderCellDef> Delete </md-header-cell>
    <md-cell *cdkCellDef="let row">
      <button (click)="deleteMember(row.$key)">Delete</button> </md-cell>
  </ng-container>

  <!-- Edit button Column -->
  <ng-container cdkColumnDef="edit">
    <md-header-cell *cdkHeaderCellDef> Edit </md-header-cell>
    <md-cell *cdkCellDef="let row">
      <button (click)="goToDetailPage(row.$key)">Edit</button> </md-cell>
  </ng-container>

  <!-- Database key Column -->

  <ng-container cdkColumnDef="key">
    <md-header-cell *cdkHeaderCellDef class="hiddenField"> Key </md-header-cell>
    <md-cell *cdkCellDef="let row" class="hiddenField"> {{row.$key}} </md-cell>
  </ng-container>


  <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
  <md-row *cdkRowDef="let row; columns: displayedColumns;"></md-row>

</md-table>

all-members.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { MembersAdminService } from './member-admin.service';
import { MembersAdminSource } from './member-admin.service';
import { ConfirmService } from '../../../shared/confirm.service';
import { Member } from './member-admin.model';

@Component({
  selector: 'app-all-members',
  templateUrl: './all-members.component.html'
})
export class AllMembersComponent implements OnInit {

  members: Member[];
  private selectedId: number;
  private result: boolean;
  allMembers: Member[];


  // For MD data table.

  private dataSource: MembersAdminSource | null;
  private displayedColumns = [
      'firstName',
      'lastName',
      'mainSkillTitle',
      'mainSkills',
      'delete',
      'edit',
      'key'
  ];


  constructor(
      private membersAdminService: MembersAdminService,
      private router: Router,
      private confirmService: ConfirmService
  ) {}

  ngOnInit() {

    this.membersAdminService.getMembers()
        .subscribe(members => {
            this.members = members;
            this.dataSource = new MembersAdminSource(members);
        });
  }

  goToDetailPage(selectedMemberKey) {
    console.log('selectedMember: ', selectedMemberKey);
    this.router.navigate(['/loggedin/admin/membersAdmin/editMember', selectedMemberKey]);
  };

  deleteMember(selectedMemberKey) {
    // Call the confirm dialog component
    this.confirmService
        .confirm('Confirm Delete', 'This action is final. Gone forever!')
        // .do();
        .do(res => {if (res === true) {
            this.membersAdminService.deleteMember(selectedMemberKey);
        }})
        .subscribe(res => this.result = res, err => err);
  }

member-admin.service.ts

import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import { FirebaseApp } from 'angularfire2';
import { Inject, Injectable } from '@angular/core';

import { Member } from './member-admin.model';
import { SuccessService } from '../../../shared/success.service';

import { DataSource } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';


@Injectable()
export class MembersAdminService {

  private members$: FirebaseListObservable<Member[]>;

  constructor(
      private af: AngularFireDatabase,
      private successService: SuccessService,

      @Inject(FirebaseApp) fb) {
        this.members$ = af.list('Members');
  }


  // Get all members.

  public getMembers(): FirebaseListObservable<any> {
    return this.af.list('Members', {
      query: {
        orderByChild: 'lastName'
      }
    });
  }


  // Fetch member detail for member list.

  public getMemberById(memberId: string) {
    return this.af.object('Members/' + memberId);
  }

  // Create new member

  public addMember(newMember: Member): void {
    this.members$.push(newMember)
        .catch(error => this.handleError(error));
  }

  // Update an existing member

  public updateMember(key: string, value: any): void {
    this.members$.update(key, value)
        .catch(error => this.handleError(error));
  }

  // Deletes a single member and calls for success modal window.

  public deleteMember(key: string): void {
    this.af.object('/Members/' + key).remove()
        .catch(error => this.handleError(error))
        .then(_ => this.success());
  }

  private success() {
    this.successService
        .openDialog('Database updated as you wished!');
  }

  // Default error handling for all actions

  private handleError(error) {
    console.log(error);
  }

}

// *** MD Data Table service. ***


export class MembersAdminSource extends DataSource<Member> {

    constructor(private members: Member[]) {
        super();
    }


    /** Connect function called by the table to retrieve one stream containing the data to render. */
    connect(): Observable<Member[]> {
        return Observable.of(this.members);
    }

    disconnect() {}
}
like image 92
Preston Avatar answered Jan 02 '23 19:01

Preston