Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

re-initialize angular 6 datatable shows this.dtElement undefined

Tags:

angular6

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> &nbsp;
                        <button type="submit" *ngIf="editFlag == true" class="btn btn-sm btn-primary" type="submit"><i class="fa fa-dot-circle-o"></i> Update</button> &nbsp;
                        <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>
                                    &nbsp;/&nbsp;
                                    <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"
like image 691
Anoop Sankar Avatar asked Jan 14 '19 05:01

Anoop Sankar


2 Answers

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);
    }
  }
like image 132
Yuk_dev Avatar answered Oct 12 '22 17:10

Yuk_dev


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
like image 43
Lucas Rassilan Vilanova Avatar answered Oct 12 '22 15:10

Lucas Rassilan Vilanova