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].
在 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].