Angular 数据表更新数据在 export/sort/search 后消失

Angular Datatable updated data disappear upon export/sort/search

在 angular 数据 table 方面,我仍然是菜鸟。我的页面在 table 中显示品种,并且可以将只读输入切换到 editable 字段并删除条目。我还希望将这些数据导出为 excel 或 pdf。我面临的问题是,在我编辑或删除之后(在 API 调用更改我的数据库中的值之后)屏幕上 table 中的数据发生了变化,但在导出时它没有更新( excel 或 pdf) 意味着导出时仅保留页面首次加载时的初始数据...
它的工作方式:一个图标使用户能够编辑 -> 用户编辑然后确认 -> API 通过该模块的服务进行调用 -> 数据更改 -> Excel/Pdf 导出仍然有相同的数据和以前一样
HTML

<table datatable [dtOptions]="dtExportButtonOptions" class="table table-bordered table-striped mb-0">
            <thead>
                <tr>
                    <th class="text-center">Breed Name</th>
                    <th class="text-center">Options</th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="let breed of BREEDS">
                    <td class="text-center">
                        <input class="form-control" type="text" placeholder="Insert Breed Name"
                            [(ngModel)]="breed.BREED_NAME" [readonly]="!breed.Edit">
                        <span style="display: none;" >{{breed.BREED_NAME}}</span>
                    </td>

                    <td class="text-center">
                        <div class="row align-items-center m-l-0">
                            <div class="col-sm-6 text-right">
                                <button *ngIf="!breed.Edit" type="button" class="btn btn-icon btn-outline-info mr-2"
                                    (click)="ToggleEdit(breed)"><i class="feather icon-edit-2"></i></button>
                                <button *ngIf="breed.Edit" type="button" class="btn btn-icon btn-outline-success mr-2"
                                    (click)="EditBreed(breed)"><i class="feather icon-check-circle"></i></button>
                            </div>
                            <div class="col-sm-6 text-left">
                                <button *ngIf="!breed.Edit" type="button" class="btn  btn-icon btn-outline-danger"
                                    (click)="OpenDeleteModal(breed)"><i class="feather icon-trash-2"></i></button>
                                <button *ngIf="breed.Edit" type="button" class="btn  btn-icon btn-outline-danger"
                                    (click)="ToggleEdit(breed)"><i class="feather icon-slash"></i></button>
                            </div>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>

类型说明

addCusForm: FormGroup;
  dtExportButtonOptions: any = {};
  DeletedBreed: Breed;
  _params_EditBreed: Breed = new Breed();
  _params_DeleteBreed: Params_Delete_Breed = new Params_Delete_Breed();
constructor(
    private proxy: Proxy,
    private fb: FormBuilder,
    private CmSvc: CommonService,
    private GSSVC: GeneralsetService
  ) { }

  ngOnInit(): void {
    this.addCusForm = this.fb.group({
      BREED_ID: [-1],
      OWNER_ID: [1],
      BREED_NAME: [, [Validators.required]],
    });

    var buttonCommon = {
      exportOptions: {
        // format: {
        //   body: function (data, row, column, node) {
        //     return node.firstChild.tagName === "INPUT" ?
        //       node.firstElementChild.value :
        //       data;
        //   }
        // },
        columns: [0],
      }
    };

    this.dtExportButtonOptions = {
      dom: 'Bfrtip',
      buttons: [
        $.extend(true, {}, buttonCommon, {
          extend: 'copyHtml5'
        }),
        $.extend(true, {}, buttonCommon, {
          extend: 'excelHtml5',
          titleAttr: 'Export to Excel',
        }),
        $.extend(true, {}, buttonCommon, {
          extend: 'print',
          titleAttr: 'Print',
        }),
      ]
    };
  }
ToggleEdit(breed) {
    breed.Edit = !breed.Edit;
  }

  EditBreed(breed: Breed) {
    if (breed.BREED_NAME.length > 0) {
      this._params_EditBreed = breed;
      console.log(this._params_EditBreed);

      this.proxy.Edit_Breed(this._params_EditBreed).subscribe((result) => {
        if (result) {
          this.CmSvc.ShowMessage('Breed ' + this._params_EditBreed.BREED_NAME + ' has been successfully Updated.',
            3500);
          this.addCusForm.get('BREED_NAME').reset();
          this.GSSVC.resolve();
        }
      });
      this.ToggleEdit(breed);
    }
  }

  SubmitBreed() {
    if (this.addCusForm.valid) {
      this._params_EditBreed = this.addCusForm.getRawValue() as Breed;
      console.log(this._params_EditBreed);

      this.proxy.Edit_Breed(this._params_EditBreed).subscribe((result) => {
        if (result) {
          this.CmSvc.ShowMessage('Breed ' + this._params_EditBreed.BREED_NAME + ' has been successfully submitted.',
            3500);
          this.addCusForm.get('BREED_NAME').reset();
          this.GSSVC.resolve();
        }
      });
    }
  }

DeleteBreed() {
    this._params_DeleteBreed.BREED_ID = this.DeletedBreed.BREED_ID;
    this.proxy.Delete_Breed(this._params_DeleteBreed).subscribe((result) => {
      if (!result) {
        this.CmSvc.ShowMessage(
          'Breed ' + this.DeletedBreed.BREED_NAME + ' has been successfully removed.',
          3500
        );
        this.modalDelete.hide();
        this.DeletedBreed = null;
        //this.ToggleEdit(breed);
        this.GSSVC.resolve();
      }
    })
  }

!!您可能会注意到我在 table HTML 中有一个隐藏的跨度。我这样做是因为 table 中没有显示输入字段,所以我读到这是一个周转解决方案。我尝试了另一种解决方案,您会在 TypeScript 文件中看到它的注释,但这并没有使我能够整理列或搜索。
这是一个“非工作”stackblitz link,可以更好地了解整个架构:https://stackblitz.com/edit/angular-bppwap?embed=1&file=src/app/hello.component.html
我希望我提供的足够多,并提前感谢您的帮助。

要更新 Angular DataTable 数据,您应该在 table 上放置一个 dtTrigger 并在必须重新加载数据时调用 next()

<table datatable 
[dtOptions]="dtExportButtonOptions" 
[dtTrigger]="dtTrigger" 
class="table table-bordered table-striped mb-0">
import { Subject } from 'rxjs';
import { DataTableDirective } from 'angular-datatables';

---

  dtTrigger: Subject<any> = new Subject<any>();
  @ViewChild(DataTableDirective, { static: false })
  dtElement: DataTableDirective;

 // Call this method to reaload the data
 reRender(): void {
    this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
      // Destroy the table first
      dtInstance.destroy();
      // Call the dtTrigger to rerender again
      this.dtTrigger.next();
    });
  }

我确实使用了 Maria 提供的 reRender 功能,但仅此还不够。 首先,我将从父组件获取数据的 API 函数移到了子组件,因为我需要在获取数据时激活 reRender 函数。 (我也可以使用 @ViewChild 从父组件激活它,但这只是为了简单起见)。

首先要补充的是

ngAfterViewInit(): void {
    this.dtTrigger.next();
    this.isfirst = false;
  }

isfirst 标志用于区分页面是否是第一次加载,因为重新渲染 onInit 会抛出错误。

下面是reRender函数

reRender(): void {
    this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
      // Destroy the table first
      dtInstance.destroy();
      // Call the dtTrigger to rerender again
      this.dtTrigger.next();
    });
  }

这就是检索数据时发生的情况

this.GSSVC.onDog_breedChange
      .pipe(takeUntil(this._unsubscribAll)).subscribe(breed => {
        if (breed) {
          this.BREEDS = breed;
          if (this.BREEDS.length === 0) {
            this.EmptyData = true;
          }
          else {
            this.EmptyData = false;
          }
          if (!this.isfirst)
            this.reRender();
        }
      });

同样重要的是要注意,我在 table 标记上有一个 ngIf 标志,以防传入数据为空。这会抛出一些错误,当我从 table 中删除所有内容然后尝试添加一个条目时显示,因此删除 ngIf 或替换为 [hidden].