Как лимитировать отображаемое количество строк в ячейке таблице в Angular ngx-bootstrap?

Есть компонент описывающий таблицу:

    @Component({
  selector: 'cmx-table',
  templateUrl: './cmx-table.component.html',
  styleUrls: ['./cmx-table.component.scss']
})
export class CmxTableComponent<T> implements OnInit, AfterViewInit {
  public readonly tableSpinnerName = Constants.TABLE_SPINNER_NAME;

  @Input() loadOnInit = true;
  @Input() loadOnPageLimitChange = true;
  @Input() useRouteForSettingsStore = true;
  @Input() isLoading = false;
  @Input() selectionType = 'checkbox';
  @Input() rowClass: string;
  @Input() countTitle = 'Всего записей';
  @Input() countTitleStringTemplate = null;
  @Input() showLastPage = true;
  @Input() showPageControls = true;
  @Input() useScrollPaging = false; // Not implemented
  @Input() clientLimitPage = false;
  @Input() groupExpansionDefault = false;
  @Input() public hiddenColumns: Array<TableColumn> = [];
  @Input() name = 'table'; // Name of table (need change if have more tables in page)
  @Input() isPersistedSorts = true;
  @Input() treeFromRelation: string;
  @Input() treeToRelation: string;
  @Input() withoutPaging = false;
  @Input() pageLimitOptions = [{ value: 25 }, { value: 50 }, { value: 100 }, { value: 500 }];
  private _tableModelInput = new BehaviorSubject<TableModel<T>>(undefined);
  @Input() set tableModelInput(value) {
    // set the latest value for _data BehaviorSubject
    if (value !== undefined) {
      this._tableModelInput.next(value);
    }
  }
  // tslint:disable-next-line:no-input-rename
  @Input('btnToolbarTemplate') public customBtnToolbarTemplate;
  // tslint:disable-next-line:no-input-rename
  @Input('groupHeader') public customGroupHeader;
  @Input() displayCheck: (row: any, column?: any, value?: any) => boolean;
  @Input() selectCheck: any;

  @Output() readonly fetchData = new EventEmitter<TableModel<T>>();
  @Output() readonly endFetchData = new EventEmitter<TableModel<T>>();
  @Output() readonly selectRow = new EventEmitter<any>();
  @Output() readonly changeHiddenColumns = new EventEmitter<any>();
  @Output() readonly treeAction = new EventEmitter<any>();

  @ViewChild('emptyTemplate', { static: true }) public emptyTemplate: TemplateRef<any>;
  @ViewChild('idAnchorEditTemplate', { static: true }) public idAnchorEditTemplate: TemplateRef<any>;
  @ViewChild('dateTemplate', { static: true }) public dateTemplate: TemplateRef<any>;
  @ViewChild('dateTimeTemplate', { static: true }) public dateTimeTemplate: TemplateRef<any>;
  @ViewChild('tooltipTemplate', { static: true }) public tooltipTemplate: TemplateRef<any>;
  @ViewChild('indexTemplate', { static: true }) public indexTemplate: TemplateRef<any>;
  @ViewChild('centerTemplate', { static: true }) public centerTemplate: TemplateRef<any>;
  @ViewChild('booleanTemplate', { static: true }) public booleanTemplate: TemplateRef<any>;
  @ViewChild('symbolicBooleanTemplate', { static: true }) public symbolicBooleanTempate: TemplateRef<any>;
  @ViewChild('headLeftTemplate', { static: true }) public headLeftTemplate: TemplateRef<any>;
  @ViewChild('codeTemplate', { static: true }) public codeTemplate: TemplateRef<any>;
  @ViewChild('htmlTemplate', { static: true }) public htmlTemplate: TemplateRef<any>;
  @ViewChild(DatatableComponent, { static: true }) table: DatatableComponent;
  @ViewChild('btnToolbarTemplate', { static: true }) public defaultBtnToolbarTemplate;
  @ViewChild('groupHeader', { static: true }) public defaultGroupHeader;
  @ViewChild('tableSpinner', { static: true }) public tableSpinner: CmxSpinnerComponent;

  public columns: Array<TableColumn> = [];
  public messages = {
    emptyMessage: 'В таблице нет данных.',
    totalMessage: 'записей'
  };
  public tableModel: TableModel<T>;
  get tableModelInput() {
    // get the latest value from _data BehaviorSubject
    return this._tableModelInput.getValue();
  }
  private pageLimitStoreName = 'table_limit';
  private pageSortStoreName = 'table_sort';
  private isSortLoadFromCookie = false; // Disable loading sorting from cookie
  public currentPageLimit: number;
  private readonly pageMaxSize = 2000;
  public readonly pageControlTemplate = '$[]';
  public get btnToolbarTemplate() {
    return this.customBtnToolbarTemplate || this.defaultBtnToolbarTemplate;
  }
  public get groupHeader() {
    return this.customGroupHeader || this.defaultGroupHeader;
  }

  constructor(
    private cd: ChangeDetectorRef,
    private logger: NGXLogger,
    private cmxTableService: CmxTableService,
    private storageService: StorageService,
    private router: Router,
    private notificationService: NotificationsService
  ) {}

  ngOnInit(): void {
    this.tableModel = new TableModel<T>();
    this.cmxTableService.getColumnSubject().subscribe(e => {
      this.logger.info('Subscribe, Table change columns');
    });
    const loadedSort = this.storageService.getSetting(this.pageSortStoreName, this.useRouteForSettingsStore);
    this._tableModelInput.subscribe(
      tableModel => {
        this.logger.debug(`CmxTableComponent loaded model:`, tableModel);
        this.tableModel = tableModel;
        this.hideSpinner();

        if (loadedSort && this.isSortLoadFromCookie) {
          this.tableModel.Sort = loadedSort;
        } else if (this.tableModel && this.sorts) {
          this.tableModel.Sort = this.sorts;
        }

        this.endFetchData.next(this.tableModel);
        this.changeLimit();
      },
      err => {
        this.logger.debug('cmx-table', 'CmxTableComponent loaded model error');
        this.hideSpinner();
      }
    );
  }

    
  ngAfterViewInit() {
    setTimeout(() => {
      this.loadStoredSettings();
      if (this.useScrollPaging) {
        this.showPageControls = false;
      }

      if (this.loadOnInit && UtilService.hasOnlyUndefinedProps(this.tableModelInput.FilterModel)) {
        this.loadPage();
      }

      if (!this.withoutPaging) {
        // Crutch for table limit set
        const pageSize = this.storageService.getSetting(this.pageLimitStoreName, this.useRouteForSettingsStore, this.pageLimitOptions[1].value);
        this.tableModel.PageSize = this.currentPageLimit = Number(pageSize);
      } else {
        this.tableModel.PageSize = this.currentPageLimit = this.pageMaxSize;
        this.showPageControls = false;
      }
    });
  }

  public onResizeColumn($event) {
    // Refresh column width in model
    this.logger.debug('cmx-table', 'onResizeColumn', $event);
    if (!$event.column) {
      return;
    }
    this.columns.forEach((col, i) => {
      let res1 = 0;
      if (col.$$id === $event.column.$$id) {
        res1 = col.width - $event.newValue;
        col.width = $event.newValue;
      }
      const col2 = this.columns[i + 1];
      if (col2) {
        col2.width = col2.width + res1;
      }
    });
  }

  /**
   * Loading page
   */
  public loadPage(pageEvent = { offset: 0 }, filter: any = null) {
    if (!this.tableModel.IsFilterValid) {
      this.logger.debug('CmxTableComponent try to load page, the tableModel is not valid', pageEvent);
      return;
    }
    this.logger.debug('CmxTableComponent load page, pageEvent: ', pageEvent);
    this.tableModel.CurrentPageNumber = pageEvent.offset;
    if (this.withoutPaging) {
      this.tableModel.PageSize = this.pageMaxSize;
    }
    this.fetchData.emit(this.tableModel);
    this.table.selected = [];
    this.selectRow.emit(this.table.selected);
    this.showSpinner();
  }

  public onChangePage($event) {
    this.logger.debug('CmxTableComponent', 'onChangePage', $event);
    if (!this.clientLimitPage) {
      this.loadPage($event);
    } else {
      this.tableModel.CurrentPageNumber = $event.offset;
    }
  }

  /**
   * Change page soring
   */
  public onSort(event) {
    this.logger.debug('CmxTableComponent', 'onSort', this.sortType, event);

    const hasChanges = this.tableModel.Sort.length !== event.sorts.length || this.tableModel.Sort.some((sort, index) => event.sorts[index].prop !== sort.prop);

    if (hasChanges) {
      this.tableModel.CurrentPageNumber = 0;
    }

    if (this.sortType === 'single') {
      this.sorts = this.tableModel.Sort = [{ prop: event.column.prop, dir: event.newValue }];
    } else {
      this.sorts = this.tableModel.Sort = event.sorts.map(sortBy => {
        return { prop: sortBy.prop, dir: sortBy.dir };
      });
    }

    if (this.isPersistedSorts) {
      this.storageService.setSetting(this.pageSortStoreName, this.tableModel.Sort, this.useRouteForSettingsStore);
    }

    this.loadPage();
  }

  ...
}

Есть компонент, который её загружает:

@Component({
  selector: 'app-suv-log',
  templateUrl: './suv-log.component.html',
  styleUrls: ['./suv-log.component.scss']
})
export class SuvLogComponent extends AbstractPageComponent<EventSuvLogModel> implements OnInit {
  @ViewChild('eventCodeTemplate', { static: true }) public eventCodeTemplate: TemplateRef<any>;
  ...
  @ViewChild('numberStrEventTemplate', { static: true }) public numberStrEventTemplate: TemplateRef<any>;
  @Input() levelFilterOnly = false;
  @Input() name = 'suv-log';
  @Input() btnToolbarTemplate;      

  public listNumberStrEvent: Array<string> = ['5', '10', '20', '50', 'все'];
  public ngSelectNumberStrEvent: Array<string> = ['10'];

  constructor(
    private service: MessageEventSuvLogService,
    private clipboardService: ClipboardService,
    private injector: Injector
  ) {
    super(service, injector);
    this.modalComponent = SuvLogModalComponent;
  }

  ngOnInit() {
    this.table.columns = [
      {
        prop: 'id',
        headerTemplate: this.table.emptyTemplate,
        cellTemplate: this.table.emptyTemplate,
        checkboxable: true,
        canAutoResize: false,
        headerCheckboxable: true,
        width: 25,
        sortable: false
      },
      {
        name: 'Действия',
        cellTemplate: this.xmlTemplate,
        width: 80,
        headerTemplate: this.table.emptyTemplate,
        prop: 'xml',
        canAutoResize: false,
        sortable: false,
        frozenLeft: false
      },      
      {
        name: 'Описание',
        prop: 'description',
        sortable: false,
        width: 900,
        cellTemplate: this.descrTemplate
      }
    ];
    this.hiddenColumns = [
      {
        name: 'Инициатор',
        prop: 'source'
      },
      ...
    ];
  }

  public getDateTimeFilter(dateTime, from, to) {
    return UtilService.getDateParams(dateTime, from, to);
  }

  public onShowFull(row) {
    const initData: ModalInitData = UtilService.cloneObject(this.initData);

    initData.mode = new ModalMode();
    initData.title = 'Просмотр';
    initData.mode.toShowMode();
    initData.form = row;

    this.modalRef = this._bsModalService.show(SuvLogModalShowComponent, {
      initialState: initData,
      class: 'modal-xl'
    });
  }

  ...

  public getRowColor(row) {
    if (row.eventCode && row.eventCode.substr(4, 3) === 'WRN') {
      return 'bg-light-warning';
    } else if (row.eventCode && row.eventCode.substr(4, 3) === 'TCH') {
      return 'bg-light-danger';
    }
  }

  public setCountStrEvent(val) {
    const numberStr: number = val ? Number(val[0]) : 10;
  }
}

В поле

name:'Описание',
     prop: 'description'

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

Загрузка идет в следующий html-шаблон:

<div class="row">
  <div class="col">
    <cmx-table
      [rowClass]="eventCodeColoringEnabled ? getRowColor : ''"
      (fetchData)="fetchData($event)"
      [showLastPage]="false"
      [hiddenColumns]="hiddenColumns"
      [sorts]="[{ prop: 'dateTime', dir: 'desc' }]"
      [loadOnInit]="false"
      [loadOnPageLimitChange]="hasCompletedSearch"
      [tableModelInput]="tableModel"
      [name]="name"
      [btnToolbarTemplate]="btnToolbarTemplate"
      [useRouteForSettingsStore]="false"
      selectionType="multiClick"
      (selectRow)="onSelectRow($event)"
    >
    </cmx-table>
  </div>
</div>

<ng-template #btnToolbarTemplate>  
  <ng-select
    #numberStrEventTemplate
    class="btn btn-primary"
    [(ngModel)]="ngSelectNumberStrEvent[0]"
    [items]="listNumberStrEvent"
    [multiple]="false"
    placeholder="Строк события"
    (change)="setCountStrEvent(numberStrEventTemplate.selectedValues)"
  ></ng-select>
</ng-template>

В шаблоне предусмотрел для выбора количества строк в ячейке таблицы <ng-select>...</ng-select> В компоненте обработчик изменения setCountStrEvent(val) И ng-select и обработчик отрабатывают.

Как на фронте менять в шаблоне таблицы отображаемое количество строк в ячейках столбца 'description'?


Ответы (0 шт):