Удаление столбца из angular таблицы mat - PullRequest
0 голосов
/ 13 марта 2020

У меня есть angular mat-таблица и кнопка для добавления или удаления столбца. У меня проблема в том, что только при удалении я получаю эту ошибку: ОШИБКА TypeError: Невозможно прочитать свойство 'columnDef' из неопределенного,

родительский компонент просто общается с API и возвращает данные во входные переменные.

прошел и не может найти данные, которые не определены, поэтому это должен быть какой-то жизненный цикл, чего я пока не понимаю , Любые идеи приветствуются.

import { Component, Inject, Input, OnDestroy, OnInit, ViewChild, Output, EventEmitter, OnChanges } from '@angular/core';
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs';
import paginationDefaults from '../../constants/pagination.config';
import { ConfigureQueryComponent } from '../configure-query/configure-query.component';
import { ColumnBuilder } from './column-builder';
import { ColumnModel } from 'src/app/models/table-definition.model';

@Component({
  selector: 'app-data-table',
  templateUrl: './data-table.component.html',
  styleUrls: ['./data-table.component.scss']
})

export class DataTableComponent implements OnDestroy, OnChanges {
  @Output() pageEvent = new EventEmitter<any>();
  @Output() sortEvent = new EventEmitter<any>();

  @Input() data: any[] = [];
  @Input() metaData: any = {};
  @Input() type: string;
  @Input() selectable: boolean;
  @Input() allColumns: any[] = [];
  @Input() availableAggregates: string[] = [];

  @ViewChild(MatSort, {static: false}) sort: MatSort;

  initialized = false;
  loading = true;
  subscriptions: Subscription[] = [];
  dataSource = new MatTableDataSource<any>();
  pageProps = paginationDefaults;
  paginator: MatPaginator;

  _allColumns: any[] = [];

  availableColumns: any[] = [];
  displayedColumns: string[] = [];
  factory = {
    sortActive: '',
    sortDirection: 'asc',
    columns: []
  };

  /**
   * @param route used to build the params
   * @param dataService the service for the api endpoints
   * @param router used to navigate to individual detail views (future implementation)
   * @param dialog Material Dialog to open the Configure Columns component
   * @param columnBuilder contains the logic to build and change the table columns
   */
  constructor(
    private route: ActivatedRoute,
    private router: Router,
    public dialog: MatDialog,
    @Inject(ColumnBuilder) public columnBuilder: ColumnBuilder
  ) {}

  /**
   * @description - subscribes to the dataService method to call updateData with the api result when it's returned.
   *  also subscribes to the subject in the columnBuilder class for when the columns are updated.
   *  put both subscriptions into an array to make managing easier.
   */
  ngOnChanges(): void {
    console.warn('ngOnChanges');

    if (!this.initialized && this.allColumns.length > 0 && this.availableAggregates.length > 0) {
      this._allColumns = this.allColumns;
      this.initialized = true;
      this.manageSubscriptions();
    }

    if (this.initialized && this.data) {
      this.updateData();
    }
  }

  /**
   * @description unsubscribes to all the subscriptions on route change
   */
  ngOnDestroy(): void {
    this.subscriptions.forEach(sub => sub.unsubscribe());
  }

  /**
   * @description - manages two subscriptions, one for listening to when data is returned and the one for listening to the column
   *  builder class for when the displayed columns, all columns, and factory columns have been updated. Pushes these to a subscriptions
   *  array to unsubscribe to all them easier when the route is changed.
   */
  manageSubscriptions() {
    this.subscriptions.forEach(sub => sub.unsubscribe());

    const columnBuilderSubscription = this.columnBuilder.columnsUpdatedSubject.subscribe((data: any) => {
      this.displayedColumns = data.displayedColumns;
      this._allColumns = data.availableColumns;
      this.factory.columns = data.factoryColumns;


      console.warn('columnBuilderSubscription', this.displayedColumns, this.factory.columns);

      this.buildTable();
    });

    this.subscriptions.push(columnBuilderSubscription);
  }

  /**
   * @description updates the data and builds columns from the service result.
   * @param res an object of the service call results, including the query params.
   */
  updateData(): void {
      this.pageProps.currentPage = this.route.snapshot.queryParams.page;

      if (this.metaData.count) {
        this.pageProps.totalRecords = this.metaData.count;
      }

      this.buildColumns();
  }

  /**
   * @description calls the setColumns function in the columnBuilder class and passes through the data and type.
   */
  buildColumns(): void {
    /**
     * @todo use this function to trigger building the table and decprecate the behavioourSubject description
     */
    this.columnBuilder.setColumns(this.data, this.type, this._allColumns);
  }

  /**
   * @description shortens the column header text to format nicely in the table
   */
  truncateText(input: string): string {
    if (input.length > 20) {
      return input.substring(0, 20) + '...';
    } else {
      return input;
    }
  }

  public setLoadingState(val: boolean) {
    this.loading = val;
  }

  /**
   * @description - opens the config query pop up and passes through all columns and the available aggregates. On close it
   *  builds the columns again.
   */
  openConfig() {
    const dialogRef = this.dialog.open(ConfigureQueryComponent, {
      id: 'QueryConfigDialog',
      width: '95%',
      data: {
        context: this.type,
        columns: this._allColumns,
        aggregates: this.availableAggregates
      }
    });

    dialogRef.afterClosed().subscribe(() => {
      this.availableColumns = JSON.parse(localStorage.getItem('COL_CONFIG')) || false;
      this.buildColumns();
    });
  }

  /**
   * @description creates a new dataSource for the table
   */
  buildTable(): void {
    this.dataSource = new MatTableDataSource<any>(this.data);
    this.dataSource.sort = this.sort;
  }

  /**
   * @description changes the route to navigate to the individual detail page
   * @param index row data uuid number
   */
  public getDetails(index: number): void {
    this.router.navigate([this.data[index].url]);
  }

  /**
   * @description handles the page event on pagination change
   * @param e material pagination details
   */
  public handlePage = (e: any) => {
    this.loading = true;

    this.pageEvent.emit({
      page: e.pageIndex,
      limit: e.pageSize
    });
  }

  public handleSortBy(e: any): void {
    this.loading = true;

    this.sortEvent.emit({
      sort: e.active,
      direction: e.direction,
      page: 0
    });

    this.factory.sortActive = e.active,
    this.factory.sortDirection = e.direction;
  }

  /**
   * @description if no data is returned from the dataService, return true.
   */
  showNoResults(): boolean {
    if (this.data === undefined) {
      return true;
    }
  }

  setDefaultColumns(columnData: ColumnModel[]) {
    const defaultColumnAmount = 8;
    const columns = this.filterOnlyStatic(columnData).splice(0, defaultColumnAmount);
    columns.forEach((c) => {
      c.show = true;
      c.index = columns.indexOf(c);
    });
    return columns;
  }

  filterOnlyStatic(columns: ColumnModel[]) {
    return columns.filter((col) => col.columnType === 'STATIC' && !col.columnDef.includes('DEVICE'));
  }
}
...