i have created a form for saving and the saved data will be displayed in the datatable at the same page. Datatable rerender() works fine with submission. but on edit rerender() showing "this.dtElement" undefined..
manage-templates.component.ts
import { Component, OnInit, ViewEncapsulation, AfterViewInit, OnDestroy, ViewChild } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
import { NotifierService } from 'angular-notifier';
import { emailTemplatesService } from '../email-templates.service';
import { Globals } from '../../app.global';
import { Subject } from 'rxjs';
import { DataTableDirective } from 'angular-datatables';
import { Router } from '@angular/router';
class Template {
template_id: string;
template_name: string;
template_desc: string;
template_status: boolean;
}
class DataTablesResponse {
data: any[];
draw: number;
recordsFiltered: number;
recordsTotal: number;
}
@Component({
selector: 'app-manage-templates',
templateUrl: './manage-templates.component.html',
styleUrls: ['./manage-templates.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ManageTemplatesComponent implements AfterViewInit, OnDestroy, OnInit {
// Creating formgroup object
createEmailTemplate = new FormGroup({
templateName: new FormControl('', [Validators.required]),
templateBody: new FormControl('', [Validators.required]),
templateDesc: new FormControl('', [Validators.required])
});
// Initializing variables
submitted = false;
editFlag = false;
@ViewChild(DataTableDirective)
dtElement: DataTableDirective;
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<Template> = new Subject();
templates: Template[];
constructor(
private http: HttpClient,
private formBuilder: FormBuilder,
private postData: emailTemplatesService,
private notifier: NotifierService,
private router: Router
) { }
ngOnInit(): void {
const that = this;
this.dtOptions = {
searching: false,
pagingType: 'full_numbers',
pageLength: 10,
serverSide: true,
processing: true,
ajax: (dataTablesParameters: any, callback) => {
that.http
.post<DataTablesResponse>(
Globals.baseAPIUrl + '/getEmailTemplates',
JSON.stringify({ dataTablesParameters })
).subscribe(resp => {
that.templates = resp.data;
callback({
recordsTotal: resp.recordsTotal,
recordsFiltered: resp.recordsFiltered,
data: []
});
});
},
columns: [
{ title: 'Template Name', data: 'template_name' },
{ title: 'Template Desc', data: 'template_desc' },
{ title: 'Status', data: 'template_status' },
]
};
}
ngAfterViewInit(): void {
this.dtTrigger.next();
}
ngOnDestroy(): void {
// Do not forget to unsubscribe the event
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();
});
}
get formfields() { return this.createEmailTemplate.controls; }
// On form submit
onSubmit() {
this.submitted = true;
if (this.createEmailTemplate.invalid) {
return;
}
this.postData.createTemplate(JSON.stringify(this.createEmailTemplate.value)).subscribe(
data => {
this.notifier.notify(data['status'], data['message']);
if (data['status'] === 'success') {
this.rerender();
}
}
);
}
// On edit button
editTemplate(template_id) {
this.postData.getTemplateDetails(template_id).subscribe(
data => {
this.createEmailTemplate.patchValue({
templateName: data['message']['0']['templateName'],
templateDesc: data['message']['0']['templateDesc'],
templateBody: data['message']['0']['templateBody']
});
this.editFlag = true;
}
);
}
loadTemplates() {
this.editFlag = false;
this.rerender();
}
}
manage-templates.component.html
<div class="animated fadeIn">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<strong>Create Email Template</strong>
</div>
<form [formGroup]="createEmailTemplate" (ngSubmit)="onSubmit()" action="" method="post" class="form-horizontal">
<div class="card-body">
<div class="form-group row">
<label class="col-md-3 col-form-label" for="select1">Template Name</label>
<div class="col-md-6">
<input type="text" formControlName="templateName" class="form-control" placeholder="Template Name"
[ngClass]="{ 'is-invalid': submitted && formfields.templateName.errors }">
<span class="invalid-feedback" *ngIf="formfields.templateName.errors">Please Enter
Template Name</span>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 col-form-label" for="select1">Template Description</label>
<div class="col-md-6">
<input type="text" formControlName="templateDesc" class="form-control" placeholder="Template Description"
[ngClass]="{ 'is-invalid': submitted && formfields.templateDesc.errors }">
<span class="invalid-feedback" *ngIf="formfields.templateDesc.errors">Please Enter
Template Description</span>
</div>
</div>
<div class="form-group row">
<label class="col-md-3 col-form-label" for="text-input">Email Body</label>
<div class="col-md-6">
<editor [(ngModel)]="dataModel" class="form-control" formControlName="templateBody"
[ngClass]="{ 'is-invalid': submitted && formfields.templateBody.errors }"></editor>
<span class="invalid-feedback" *ngIf="formfields.templateBody.errors">Email body need
not be empty</span>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" *ngIf="editFlag == false" class="btn btn-sm btn-primary" type="submit"><i class="fa fa-dot-circle-o"></i> Submit</button>
<button type="submit" *ngIf="editFlag == true" class="btn btn-sm btn-primary" type="submit"><i class="fa fa-dot-circle-o"></i> Update</button>
<button type="reset" class="btn btn-sm btn-danger" *ngIf="editFlag == false"><i class="fa fa-ban"></i> Reset</button>
<button type="reset" class="btn btn-sm btn-danger" *ngIf="editFlag == true" (click)="loadTemplates()"><i class="fa fa-ban"></i> Cancel</button>
</div>
</form>
</div>
</div>
</div>
<!--/.row-->
<div class="row" *ngIf="editFlag == false">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<i class="fa fa-align-justify"></i> Email Templates
</div>
<div class="card-body template_list">
<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="row-border hover" width="100%">
<thead>
<tr>
<th>Template Name</th>
<th>Template Desc</th>
<th>Template Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody *ngIf="templates?.length != 0">
<tr *ngFor="let template of templates">
<td>{{ template.template_name }}</td>
<td>{{ template.template_desc }}</td>
<!-- <td>{{ template.template_status }}</td> -->
<td>
<span *ngIf="template.template_status == true" class="badge badge-success"> Active </span>
<span *ngIf="template.template_status == false" class="badge badge-danger">Inactive</span>
</td>
<td>
<a routerLink="edit" (click)="editTemplate(template.template_id)">Edit</a>
/
<a routerLink="disable/{{template.template_id}}" *ngIf="template.template_status == true">Deactivate</a>
<a routerLink="enable/{{template.template_id}}" *ngIf="template.template_status == false">Activate</a>
</td>
</tr>
</tbody>
<tbody *ngIf="templates?.length == 0">
<tr>
<td colspan="3" class="no-data-available">No data!</td>
</tr>
<tbody>
</table>
</div>
</div>
</div>
</div>
</div>
on editing an email template datatable hides and the values displayed in the form. Here i haven't write code for update form values. I want to repopulate the page on pressing "Cancel" button. On cancel button content in the datatable repopulates without pagination or any styles of datatable.
ERROR TypeError: "this.dtElement is undefined"
Here is my solution, the order of ViewChild/dtElement/... is important in this case
export class DemoComponent implements OnInit {
@ViewChild(DataTableDirective)
dtElement: DataTableDirective;
dtOptions: any = {};
dtInstance: DataTables.Api;
dtTrigger: Subject<any> = new Subject();
dt_data: any = {};
......
ngOnInit() {
this.dtOptions = {
...
};
}
ngAfterViewInit(){
//Define datatable
this.dtTrigger.next();
}
ngOnDestroy(): void {
this.dtTrigger.unsubscribe();
}
SomeFunction(){
//return the updated record, all the update function must be using rerender
this.dt_data = resp;
this.rerender();
}
rerender(): void {
try {
this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
// Destroy the table first
dtInstance.destroy();
// Call the dtTrigger to rerender again
this.dtTrigger.next();
});
} catch (err) {
console.log(err);
}
}
When I faced this same issue, I managed to solve it by using [hidden] instead of *ngIf. Aparently, ViewChild couldn't find the DataTableDirective because it wasn't in the HTML (thanks to *ngIf) resulting in the error, since this.dtElement was equal to undefined.
I suggest you try using this:
<div class="row" [hidden]="editFlag == true">
<!-- DataTable Content -->
</div
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With