Esco
Esco

Reputation: 397

How to check if element is rendered in angular 2

I want to show a popup after table is completely loaded. Am using load property but it is not working. Is there any other way to achieve this? Without parent-child concept.

following is my code component.ts

export class FileUploadComponent {
    public files: UploadFile[] = [];
    data: AOA = [ [1, 2], [3, 4] ];
    wopts: XLSX.WritingOptions = { bookType: 'xlsx', type: 'array' };
    fileName: string = 'SheetJS.xlsx';
    showData: boolean = false;

    public dropped(event: UploadEvent) {
       this.files = event.files;
       for (const droppedFile of event.files) {
         if (droppedFile.fileEntry.isFile) {
           const reader: FileReader = new FileReader();
           const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
           fileEntry.file((file: File) => {
              var filePath = file;
             reader.onload = (e: any) => {
              const bstr: string = e.target.result;
              const wb: XLSX.WorkBook = XLSX.read(bstr, {type: 'binary'});
              const wsname: string = wb.SheetNames[0];
              const ws: XLSX.WorkSheet = wb.Sheets[wsname];
              this.data = <AOA>(XLSX.utils.sheet_to_json(ws, {header: 1}));
            };
            reader.readAsBinaryString(file);
            this.showData = true;
            this.infoModal.hide();
          });
       } else {
          this.showData = false;
          const fileEntry = droppedFile.fileEntry as FileSystemDirectoryEntry;
       }
     }
   }

  showPopUp(){ 
     console.log('yes');
  }
}

Following is my component.htm

      <div class="modal-body">
        <file-drop id="infoFileModal" headertext="Drop files here" (onFileDrop)="dropped($event)" (onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)"></file-drop>
      </div>

 <div class="card-body">
   <div *ngIf="showData" class="upload-table  table-responsive">
     <table #table class="table-bordered table-striped" id="dest_table" (load)="showPopup()">
        <tr *ngFor="let row of data">
           <td *ngFor="let val of row">
              {{val}}
           </td>
        </tr>
     </table>
  </div>
  <div *ngIf="!showData" class="div-upload">
     No Data Found
  </div>
 </div>

Upvotes: 1

Views: 15865

Answers (3)

user6749601
user6749601

Reputation:

Okay, so here is another approach.

As your table takes several minutes for rendering, after the data-array has been filled, your only chance is to listen to the change-event as long as it takes. To prevent the showPopUp()-method from being fired with every finished iteration, you use Observable.debounceTime(), which only calls the method when the time past after the last change-event is greater than the given time in milliseconds.

Component

import { Component, OnInit, OnDestroy, ViewChild, AfterViewInit} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {Subscription} from "rxjs/Subscription";

 @ViewChild('table') table: any;
 private timer= Observable.timer(1000); // wait one second before calling the method
 private subscription: Subscription;

 ngOnDestroy(): void {
    if(this.subscription){
        this.subscription.unsubscribe();
    }
 }

public dropped(event: UploadEvent) {
        // ...

        reader.readAsBinaryString(file);
        this.showData = true;
        this.infoModal.hide();

        // call the watcher with a delay of one second
        // in order to give angular enough time to build up the table
        this.subscription = this.timer.subscribe( () => {
            this.triggerTableWatcher();
        });

        // ...

}


triggerTableWatcher() {
    // define the object to listen to
    const trigger = this.table.changes();

    // define the debounce-time (adjust it, if it doesn't fit your needs)
    const debounceAt = trigger.debounceTime(1000);

    // subscribe to the trigger and tell which method to call eventually
    debounceAt.subscribe(() => this.showPopUp());
}

HTML-Template (only the important part of it)

<div class="card-body">
   <div *ngIf="showData" class="upload-table  table-responsive">
      <table #table class="table-bordered table-striped" id="dest_table">
         <tr *ngFor="let row of data">
              <td *ngFor="let val of row">
                {{val}}
             </td>
         </tr>
     </table>
</div>

Upvotes: 1

user6749601
user6749601

Reputation:

You can subscribe to the onloadend()-method of FileReader. Please look at the commented part of the code.

 public dropped(event: UploadEvent) {
     this.files = event.files;
     for (const droppedFile of event.files) {
       if (droppedFile.fileEntry.isFile) {
         const reader: FileReader = new FileReader();
         const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
         fileEntry.file((file: File) => {
            var filePath = file;
           reader.onload = (e: any) => {
            const bstr: string = e.target.result;
            const wb: XLSX.WorkBook = XLSX.read(bstr, {type: 'binary'});
            const wsname: string = wb.SheetNames[0];
            const ws: XLSX.WorkSheet = wb.Sheets[wsname];
            this.data = <AOA>(XLSX.utils.sheet_to_json(ws, {header: 1}));
          };
          reader.readAsBinaryString(file);

          // subscribe to the onloadend()-method here
          reader.onloadend = (e) => {
            this.showPopUp();
          };

          this.showData = true;
          this.infoModal.hide();
        });
     } else {
        this.showData = false;
        const fileEntry = droppedFile.fileEntry as FileSystemDirectoryEntry;
     }
   }
 }

 showPopUp(){ 
    console.log('yes');
 }

Upvotes: 0

David Votrubec
David Votrubec

Reputation: 4166

Native table does not have any load event. This logic should be delegated to the service which loads the data.

Or, as suggested in the comment, you can use ngAfterViewInit(). But: If the table has been first rendered, and the you load data, then it will not work

Upvotes: 1

Related Questions