J'ai créé un formulaire de sauvegarde et les données enregistrées seront affichées dans la table de données sur la même page. Datatable rerender () fonctionne très bien avec la soumission. mais lors de l'édition, rerender () affiche "this.dtElement" non défini.
manage-templates.component.ts
ERROR TypeError: "this.dtElement is undefined"
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>
lors de la modification d'un modèle d'e-mail pouvant être daté cache et les valeurs affichées dans le formulaire. Ici, je n'ai pas écrit de code pour les valeurs du formulaire de mise à jour. Je veux repeupler la page en appuyant sur le bouton "Annuler". Sur annuler le contenu du bouton dans la table de données se remplit sans pagination ni aucun style de table de données.
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(); } }
3 Réponses :
Voici ma solution, l'ordre de ViewChild / dtElement / ... est important dans ce cas
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); } }
Si vous utilisez Forms et que chaque fois que vous soumettez de nouvelles données et données provenant de la demande de publication est différent, vous pouvez utiliser quelque chose comme ceci (angulaire 8) -
export class Demo implements OnDestroy, OnInit, AfterViewInit { //this part did the job for me @view... @ViewChild(DataTableDirective, { static: false }) datatableElement: DataTableDirective; dtElement: DataTableDirective; dtOptions: any = {}; dtInstance: DataTables.Api; dtTrigger: Subject<any> = new Subject(); dt_data: any = {}; ...... ngOnInit() { this.dtOptions = { paging: false, "ordering": false, dom: 'Bfrtip', buttons: [ 'copy', 'csv', 'excel' ] }; } ngAfterViewInit(){ this.dtTrigger.next(); } ngOnDestroy(): void { this.dtTrigger.unsubscribe(); } getData(){ //post request and when assigning data to variable this.dt_data = resp; this.rerender(); } rerender(): void { //this.datatableElement is important this.datatableElement.dtInstance.then((dtInstance: DataTables.Api) => { dtInstance.destroy(); this.dtTrigger.next(); }); }
Quand j'ai rencontré ce même problème, j'ai réussi à le résoudre en utilisant [hidden] au lieu de * ngIf. Apparemment, ViewChild n'a pas pu trouver le DataTableDirective car il n'était pas dans le HTML (grâce à * ngIf) entraînant l'erreur, car this.dtElement était égal à undefined.
Je vous suggère d'essayer d'utiliser ceci: p >
<div class="row" [hidden]="editFlag == true"> <!-- DataTable Content --> </div
@AnoopSanker Avez-vous déjà trouvé la solution?
@YukwongTsang Pas vraiment. J'ai divisé le processus en deux composants, l'un pour l'enregistrement et l'autre pour l'édition / la mise à jour. Les deux utilisent le même fichier html. (Je sais que les solutions que j'ai appliquées ne sont pas une bonne façon)
@AnoopSanker Merci pour la réponse, j'ai l'impression de trouver la solution et cela peut vous aider aussi