Closed iCrash91 closed 6 years ago
Angular and DataTables do not work on the same "data", ie any changes on Angular won't be impacted on DataTables. After you add your row, you need to rerender your DataTable so that DataTables acknowledges the changes.
Unfortunately, it's not really smooth and performant as it will rerender the whole DataTables instead of just adding/removing rows... I don't have any alternative solution.
this is a problem for our project, many tables need to play with dynamic data, so we decided to stop using this. the glitch it's making while rerendering is not a good user experience.
so datatables must be used with static data only.
Another approach is to not use the angular renderer, but using the DataTable's API to add rows. This way, your table will be fully updated.
you will need to destroy your datatable before you run this.dtTrigger.next(); when data is updated ->
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
// first destroy table
dtInstance.destroy();
// get your data function call here
});
might do the trick...
update: i use it this way in my application works just fine when rows added or deleted the it will rerender table as written in above comments not that "beautiful" experience..
it doesnt work for me
dtTrigger: Subject
this.lacuneTable.dtInstance.then dtInstance is null each time
i have many datable in my component and i need to specify the one that is dynamic
how can i do it?
Could you post a plunker or something similar?
i don't really know how to build up a project for Angular5 + Datatables in plunkr sorry but here is the code
HTML
<table datatable [dtOptions]="options" [dtTrigger]="trigger" class="table table-sm table-bordered table-hover table-striped">
<thead>
<tr>
<th>Numéro</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let lacune of lacunes" class="table-row-clickable" (click)="voirLacune(lacune)">
<td>{{lacune.numero}}</td>
<td [innerHTML]="lacune.description"></td>
</tr>
</tbody>
</table>
Component
trigger = new Subject<any>();
ngOnInit(): void {
this.route.params.subscribe(params => {
forkJoin(
this.appreciationsService.obtenirListe(),
this.recommandationsService.obtenir(+params['id'])
).subscribe(reponse => {
this.recommandation = reponse[1];
this.lacunes = this.recommandation.lacunes;
this.trigger.next(); // This doesnt render the datatables nor does it show sort arrow on table and it doesnt add datatables class to the table
});
});
}
ngAfterViewInit doesn't work for us, because we are loading data async and the AfterViewInit were called before data were back from server.
the this.trigger.next) in ngOnInit doesn't work either, while debugging the datables pluggin doesnt receive the next() event.
so we ended replacing the this.trigger.next() to
setTimeout(function() {
this.trigger.next();
}.bind(this));
and now it's working as expected
For information, you can use this plnkr template to demonstrate your issue.
@s3rkan how did you get a reference to your dtElement?
I'm kind of confused. So what this library actually does "in Angular way"? It seems like nothing else than a glorified wrapper over DataTable's API, but what's the point if it cannot properly rerender the data angular ngFor is generating? That destroy/create technique is hack at best. Is there no other way?
it seems that the original library is using the same way to regenerate the data if you dont use the column data way.
It seems like nothing else than a glorified wrapper over DataTable's API
It is just a wrapper over DataTable's API.
what's the point if it cannot properly rerender the data angular ngFor is generating? That destroy/create technique is hack at best.
Unfortunately, it's been quite a time since I "touched" the frontend development (because it's moving so fast and it's not really my "expertise" and I don't have much time this year), that's why there are no improvement in this wrapper for quite some time... But, pull requests are always welcome :)
And you can check the code it's pretty straight forward.
i'm also having the same problem, reloading the data is not binding properly. Its disappeared immediately
if it can be used only with static data then it should be given with big heading on front page of it
Same here... my scenario: Im using datatables on a child component, and i have a change detection using DoCheck When i rerender the new row get deleted even from the dom...
@ViewChild(DataTableDirective)
dtElement: DataTableDirective;
differ: any;
first: Boolean = true;
@Input() labels: string[] = ['Label 1', 'Label 2', 'Label 3'];
@Input() rows: string[][] = [
['Test 1', 'Test 2', 'Test 3'],
['Prueba 1', 'Prueba 2', 'Prueba 3']
];
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
constructor(private _iterableDiffers: IterableDiffers ) {
this.differ = this._iterableDiffers.find([]).create(null);
this.dtOptions = {
pageLength: 20
};
}
ngDoCheck() {
const change = this.differ.diff(this.rows);
if (change && !this.first) {
this.rerender();
}
this.first = false;
}
ngAfterViewInit(): void {
this.dtTrigger.next();
}
ngOnDestroy(): void {
this.dtTrigger.unsubscribe();
}
rerender(): void {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
// Destroy the table first
dtInstance.destroy();
// Call the dtTrigger to rerender again
// this.dtTrigger.next();
});
}
It is weird because if i dont destroy the datatable the row shows, but i cant search or use the datatable but when i destroy it it the destroy the new data and change it to where the datatable was initialized.
@pktron I've found a way to make it work i think for you!
put everything that is in your rerender() method in a setTimeout
rerender(): void {
setTimeout(() => {
// put rest of the code here
});
}
I solved it using that approach @Korigoth thanks a lot!
@pktron np ;) it doesn't solve all the problem but it help in 95% of the case !
So I have been running into the same issue but my solution is a little different. It seems that the rerender in the docs isn't quite good enough when loading from a remote source. The trick that I found is to remove the table from the dom and then put it back before calling the dtTrigger.next().
This seems to fix all the issues I was having so hopefully it can help someone else too.
My Code
buildDtOptions() {
this.dtOptions = {
dom: '<"row"<"col-sm-12"B>>' +
'<"row"<"col-sm-12 col-md-6"l><"col-sm-12 col-md-6"f>>' +
'<"row"<"col-sm-12 table-responsive"tr>>' +
'<"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>',
buttons: [
{
extend: 'colvis',
},
{
extend: 'csv',
},
{
extend: 'pdfHtml5',
orientation: 'landscape',
title: 'welcome-call',
filename: 'welcome-call',
extension: '.pdf',
exportOptions: {
columns: ':visible'
}
}
]
};
}
ngOnInit() {
this.buildDtOptions();
this.loadWelcomeCalls();
}
loadWelcomeCalls() {
this.welcomeCallService.getParentWelcomeCalls(this.filters).subscribe(response => {
this.welcome_calls = response.results;
this.rerender();
});
}
rerender(): void {
if (this.dtElement && this.dtElement.dtInstance) {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
dtInstance.destroy();
});
}
this.loading = true;
this.loading = false;
setTimeout(() => {
this.dtTrigger.next();
});
}
So I have been running into the same issue but my solution is a little different. It seems that the rerender in the docs isn't quite good enough when loading from a remote source. The trick that I found is to remove the table from the dom and then put it back before calling the dtTrigger.next().
This seems to fix all the issues I was having so hopefully it can help someone else too.
My Code
buildDtOptions() { this.dtOptions = { dom: '<"row"<"col-sm-12"B>>' + '<"row"<"col-sm-12 col-md-6"l><"col-sm-12 col-md-6"f>>' + '<"row"<"col-sm-12 table-responsive"tr>>' + '<"row"<"col-sm-12 col-md-5"i><"col-sm-12 col-md-7"p>>', buttons: [ { extend: 'colvis', }, { extend: 'csv', }, { extend: 'pdfHtml5', orientation: 'landscape', title: 'welcome-call', filename: 'welcome-call', extension: '.pdf', exportOptions: { columns: ':visible' } } ] }; } ngOnInit() { this.buildDtOptions(); this.loadWelcomeCalls(); } loadWelcomeCalls() { this.welcomeCallService.getParentWelcomeCalls(this.filters).subscribe(response => { this.welcome_calls = response.results; this.rerender(); }); } rerender(): void { if (this.dtElement && this.dtElement.dtInstance) { this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => { dtInstance.destroy(); }); } this.loading = true; this.loading = false; setTimeout(() => { this.dtTrigger.next(); }); }
This what was that help me, Thank you a lot man.
@Korigoth
setTimeout(function() { this.trigger.next(); }.bind(this));
this is worked for me Thanks for the suggestion.
I'm submitting a...
What versions you are using?
Current behavior
When I load the datatable the first time, everything works propertly, but if I add / edit or delete a new row using http, the data changes but the table doesn't recognize it. For example, If the table is empty it shows "No data available in table", after I push a new row to my array, I can see the row but also the "no data available" message,in the footer still displays "showing 0 to 0 of 0 entries" and I can't use the search bar to find the new row because it says no results. I tried using the rerender method as shown in the documentation, but after the rerender the new data disappear.
First time the table is loaded
After the data is addes
Expected behavior
The table should recognize the changes made to the data in the table.
Minimal reproduction of the problem with instructions
This is my component
Methods in my service to send and load the data
Template