具有骨架效果而不是加载圆的PrimeNG DataTable

PrimeNG DataTable with a skeleton effect instead of loading circle

如何使用skeleton loader? If you look at the following docs link制作DataTable(PrimeNG),我现在的加载效果是这样的。

PrimeNG 实际上自己实现了骨架效果 here,但我在那里找不到 StackBlitz 或代码片段。

查看-lecturers.component.ts

import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { Lecturer } from '../lecturer';
import { LecturerService } from '../lecturer.service';
import { ConfirmationService, MessageService, PrimeNGConfig } from 'primeng/api';
import { BreadcrumbService } from '@core/services';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { Table } from 'primeng/table';

@Component({
  selector: 'app-view-lecturers',
  templateUrl: './view-lecturers.component.html',
  providers: [MessageService, ConfirmationService]
})
export class ViewLecturersComponent implements OnInit, OnDestroy {

  lecturerDialog: boolean;
  lecturers: Lecturer[];
  lecturer: Lecturer;
  selectedLecturers: Lecturer[];
  submitted: boolean;
  loading: boolean = true;

  private componentDestroyed$ = new Subject<boolean>();

  @ViewChild('dt') table: Table;

  constructor(
    private lecturerService: LecturerService,
    private messageService: MessageService,
    private confirmationService: ConfirmationService,
    private breadcrumbService: BreadcrumbService,
    private primengConfig: PrimeNGConfig) {
    this.breadcrumbService.setItems([
      { label: 'Преподаватели' },
      { label: 'Преглед' }
    ]);
  }

  ngOnInit() {
    this.lecturerService.getLecturers()
      .pipe(takeUntil(this.componentDestroyed$))
      .subscribe(data => {
        setTimeout(() => {
          this.lecturers = data;
          this.loading = false;
        }, 1000);
      });

    this.primengConfig.ripple = true;
  }

  ngOnDestroy() {
    this.componentDestroyed$.next(true);
    this.componentDestroyed$.complete();
  }

  applyFilterGlobal($event: any) {
    this.table.filterGlobal(($event.target as HTMLInputElement).value, 'contains');
  }

  openNew() {
    this.lecturer = {};
    this.submitted = false;
    this.lecturerDialog = true;
  }

  deleteSelectedLecturers() {
    this.confirmationService.confirm({
      message: 'Сигурни ли сте, че искате да изтриете данните за избраните преподаватели?',
      header: 'Потвърждение',
      icon: 'pi pi-exclamation-triangle',
      acceptLabel: 'Да',
      rejectLabel: 'Не',
      accept: () => {
        this.lecturers = this.lecturers.filter(val => !this.selectedLecturers.includes(val));
        this.selectedLecturers = [];
        this.messageService.add({ severity: 'success', summary: 'Успешно', detail: 'Данните за преподавателите са изтрити', life: 3000 });
      }
    });
  }

  editLecturer(lecturer: Lecturer) {
    this.lecturer = { ...lecturer };
    this.lecturerDialog = true;
  }

  deleteLecturer(lecturer: Lecturer) {
    this.confirmationService.confirm({
      message: 'Сигурни ли сте, че искате да изтриете данните за ' + lecturer.displayName + '?',
      header: 'Потвърждение',
      icon: 'pi pi-exclamation-triangle',
      acceptLabel: 'Да',
      rejectLabel: 'Не',
      accept: () => {
        this.lecturers = this.lecturers.filter(val => val.id !== lecturer.id);
        this.lecturer = {};
        this.messageService.add({ severity: 'success', summary: 'Успешно', detail: 'Данните за преподавателя са изтрити', life: 3000 });
      }
    });
  }

  hideDialog() {
    this.lecturerDialog = false;
    this.submitted = false;
  }

  saveLecturer() {
    this.submitted = true;

    if (this.lecturer.fullName?.trim() && this.lecturer.displayName?.trim()) {
      if (this.lecturer.id) {
        this.lecturers[this.findIndexById(this.lecturer.id)] = this.lecturer;
        this.messageService.add({ severity: 'success', summary: 'Successful', detail: 'Данните за преподавателя са обновени', life: 3000 });
      }
      else {
        this.lecturers.push(this.lecturer);

        // update to what's in db instead

        this.messageService.add({ severity: 'success', summary: 'Successful', detail: 'Преподавателят е добавен', life: 3000 });
      }

      this.lecturers = [...this.lecturers];
      this.lecturerDialog = false;
      this.lecturer = {};
    }
  }

  findIndexById(id: number): number {
    let index = -1;
    for (let i = 0; i < this.lecturers.length; i++) {
      if (this.lecturers[i].id === id) {
        index = i;
        break;
      }
    }

    return index;
  }

}

查看-lecturers.component.html

<div class="p-grid">
  <div class="p-col-12">

    <p-toast></p-toast>

    <div class="card">
      <p-toolbar styleClass="p-mb-4">
        <ng-template pTemplate="left">
          <button pButton pRipple label="Добавяне" icon="pi pi-plus" class="p-button-success p-mr-2 p-mb-2"
            (click)="openNew()"></button>
          <button pButton pRipple label="Изтриване" icon="pi pi-trash" class="p-button-danger p-mb-2"
            (click)="deleteSelectedLecturers()" [disabled]="!selectedLecturers || !selectedLecturers.length"></button>
        </ng-template>
      </p-toolbar>

      <p-table #dt [value]="lecturers" [(selection)]="selectedLecturers" dataKey="id" styleClass="p-datatable-lecturers"
        [rowHover]="true" [rows]="10" [showCurrentPageReport]="true" [rowsPerPageOptions]="[10,25,50]"
        [loading]="loading" [paginator]="true"
        currentPageReportTemplate="Показват се от {first} до {last} от общо {totalRecords} записа"
        [globalFilterFields]="['fullName','displayName']">
        <ng-template pTemplate="caption">
          <div class="p-d-flex p-flex-column p-flex-md-row p-jc-md-between table-header">
            <h5 class="p-m-0">Преподаватели</h5>
            <span class="p-input-icon-left">
              <i class="pi pi-search"></i>
              <input pInputText type="text" (input)="applyFilterGlobal($event)" placeholder="Търсене..." />
            </span>
          </div>
        </ng-template>
        <ng-template pTemplate="header">
          <tr>
            <th style="width: 3rem">
              <p-tableHeaderCheckbox></p-tableHeaderCheckbox>
            </th>
            <th pSortableColumn="fullName">Име <p-sortIcon field="fullName"></p-sortIcon>
            </th>
            <th pSortableColumn="displayName">Псевдоним <p-sortIcon field="displayName"></p-sortIcon>
            </th>
            <th></th>
          </tr>
        </ng-template>
        <ng-template pTemplate="body" let-lecturer>
          <tr>
            <td>
              <p-tableCheckbox [value]="lecturer"></p-tableCheckbox>
            </td>
            <td>
              {{lecturer.displayName}}
            </td>
            <td>
              {{lecturer.fullName}}
            </td>
            <td>
              <button pButton pRipple icon="pi pi-pencil" class="p-button-rounded p-button-success p-mr-2"
                (click)="editLecturer(lecturer)"></button>
              <button pButton pRipple icon="pi pi-trash" class="p-button-rounded p-button-warning"
                (click)="deleteLecturer(lecturer)"></button>
            </td>
          </tr>
        </ng-template>
        <ng-template pTemplate="summary">
          <div class="p-d-flex p-ai-center p-jc-between">
            Общо {{lecturers ? lecturers.length : 0 }} преподаватели.
          </div>
        </ng-template>
      </p-table>
    </div>

    <p-dialog [(visible)]="lecturerDialog" [style]="{width: '450px'}" header="Данни за преподавател" [modal]="true"
      styleClass="p-fluid">
      <ng-template pTemplate="content">
        <div class="p-field">
          <label for="fullName">Име</label>
          <input #fullName="ngModel" id="fullName" type="text" pInputText [(ngModel)]="lecturer.fullName"
            [ngClass]="{'ng-dirty': (fullName.invalid && submitted) || (fullName.dirty && fullName.invalid)}" required
            autofocus />
          <small class="p-error" *ngIf="(fullName.invalid && submitted) || (fullName.dirty && fullName.invalid)">Името е
            задължително.</small>
        </div>
        <div class="p-field">
          <label for="displayName">Псевдоним</label>
          <input #displayName="ngModel" id="displayName" type="text" pInputText [(ngModel)]="lecturer.displayName"
            [ngClass]="{'ng-dirty': (displayName.invalid && submitted) || (displayName.dirty && displayName.invalid)}"
            required />
            <small class="p-error" *ngIf="(displayName.invalid && submitted) || (displayName.dirty && displayName.invalid)">Псевдонимът е задължителен.</small>
        </div>
      </ng-template>

      <ng-template pTemplate="footer">
        <button pButton pRipple label="Отказ" icon="pi pi-times" class="p-button-text" (click)="hideDialog()"></button>
        <button pButton pRipple label="Запази" icon="pi pi-check" class="p-button-text"
          (click)="saveLecturer()"></button>
      </ng-template>
    </p-dialog>

    <p-confirmDialog [style]="{width: '450px'}"></p-confirmDialog>
  </div>
</div>

将此模板添加到您的 table。当 loading 属性为 true 时,它​​将在 table 内显示此模板。查看模板和 loadingbody 模板的官方文档 link

<ng-template pTemplate="loadingbody">
    <tr>
      <td><p-skeleton></p-skeleton></td>
    </tr>
</ng-template>