1

I'm trying to display some verbose logs to te user while processing a file.

I have a *ngFor='let log of _loggerService.logs' in a div. Then I select a file from an input, reads it (it's a csv) and log each row with

this._loggerService.verbose(`pushing row ${JSON.stringify(row)}`);

However, the div only appears once all rows of the file are processed rather than displaying one row at a time.

Here is my logger service:

@Injectable()
export class LoggerService {

    constructor(private changeDetectorRef: ChangeDetectorRef) { }

    private logs: ILog[] = [];

    private log(log: ILog) {
        this.logs.push(log);    
        this.logs = this.logs.slice();
        this.changeDetectorRef.markForCheck();
    }
}


UPDATE:

It works if I await say 5ms between each row processing (and hence logging).
Note that I actually removed the ChangeDetectorRef field as it is not required.

5
  • Can you add a code where you parse the file? It can be because the file parse process is UI-blocking. Commented Oct 31, 2017 at 14:14
  • Why don't try to use a pagination on scroll it will also solve the problem. Commented Oct 31, 2017 at 14:22
  • @EbraheemAlrabee' Any docs to share on this? Commented Oct 31, 2017 at 14:25
  • If you are using Material they have mat-paginator, If you don't I can add a piece of code that I have used. Commented Oct 31, 2017 at 14:28
  • I'm not using material, so please do :-) Commented Oct 31, 2017 at 14:30

1 Answer 1

1

I have used this code for log pagination

This is a custom tag for pagination

import {
  Component,
  Input, Output,
  ViewEncapsulation,
  EventEmitter,
  SimpleChanges,
  HostListener, ElementRef
} from '@angular/core';

@Component({
  selector: 'pagination',
  styles: [`
      .container {
        align-items: center;
        justify-content: flex-end;
      }
  `],
  template: `
      <div layout="row" class="container">
        <div >{{currentRow}}-{{ min( (currentRow + this.perPage - 1), total)}} of {{total | formattedNumber}}</div>
        <button [disabled]="this.currentRow==1" (click)="addToCurrent(-1)"><</button>
        <button [disabled]="this.total < (this.currentRow + this.perPage) " (click)="addToCurrent(1)">></button>
      </div>
    `
})


export class PaginationComponent {
  @Input('total')
  public total: number = 0;

  @Input('per-page')
  perPage: number = 20;

  @Input('current-row')
  currentRow: number = 1;


  @Input('scroll-area')
  scrollAreaElementRef: any;

  get currentPage(): number {
    return (this.currentRow - 1 / this.perPage) + 1;
  };

  @Output('page-change')
  pageChange: EventEmitter<PageParams> = new EventEmitter<PageParams>();

  pageSeries: number[] = new Array<number>();


  @HostListener('window:mousewheel', ['$event']) onMouseWheelChrome(event: any) {
    this.mouseWheelFunc(event);
  }

  @HostListener('window:DOMMouseScroll', ['$event']) onMouseWheelFirefox(event: any) {
    this.mouseWheelFunc(event);
  }

  @HostListener('window:onmousewheel', ['$event']) onMouseWheelIE(event: any) {
    this.mouseWheelFunc(event);
  }



  mouseWheelFunc(event) {
    //Guess the delta.
    let delta = 0;
    if (event.wheelDelta) {
      delta = -1 * event.wheelDelta / 120;
    } else if (event.detail) {
      delta = event.detail / 3;
    }

    if (this.scrollAreaElementRef != null && event.target != null) {
      if (!this.isDescendant(this.scrollAreaElementRef, event.target)) {
        return false;
      } else {
        if (event.preventDefault)
          event.preventDefault();
      }
    }

    let newRow = (this.currentRow + ((delta > 0 ? Math.ceil(delta) : Math.floor(delta)) * this.perPage));
    this.gotoRow(newRow);
  }

  isDescendant(parent, child): boolean {
    let node = child.parentNode;
    while (node != null) {
      if (node == parent) {
        return true;
      }
      node = node.parentNode;
    }
    return false;
  }


  min(v: number, v2: number) {
    if (v < v2)
      return v;
    else
      return v2;
  }


  gotoRow(row: number) {
    // set min
    if (row < 1)
      row = 1;

    // set max
    if (row > (this.total - this.perPage + 1))
      row = (this.total - this.perPage + 1);

    this.pageChange.emit(new PageParams(row, this.perPage));
  }

  addToCurrent(val: number) {
    this.gotoRow(this.currentRow + (val * this.perPage));
  }

  constructor() {

  }
}

export class PageParams {
  constructor(
    public start: number,
    public pageSize: number) {

  }
}

And put that code inside your page

<div class="" layout="column" style="align-items: stretch; width: 50%">
    <div #dataCard>
        <div layout="row" style="align-items: center;justify-content: start;">
            <div class="md-title"> Job Logs </div>
            <pagination style="width:auto;margin-left: auto" [total]="totalRows" [per-page]="rowsPerPage" [current-row]="rowStart" [scroll-area]="dataCard"
                (page-change)="pageChange($event)"></pagination>
        </div>
        <pre style="margin-top: 0px;">
            <div *ngFor="let i of displayIndexArray" class="app-content" layout="row" style="align-items: stretch;">
                <ng-template [ngIf]="displayArray[i]?.log === null || displayArray[i]?.log === ''"><br/></ng-template>
                <ng-template [ngIf]="displayArray[i]?.log != null && displayArray[i]?.log != ''"><span>{{ displayArray[i]?.log }}</span></ng-template>
            </div>
        </pre>
    </div>
</div>

And this code inside page ts file

private _rowsPerPage: number = 34;
private _totalRows: number = 0;
private _rowStart: number = 1;
private displayArray: Log[] = new Array(this._rowsPerPage).fill(undefined);
private displayIndexArray: number[] = new Array(this._rowsPerPage).fill(0).map((x, i) => i);

get rowsPerPage(): number {
    return this._rowsPerPage;
}

get rowStart(): number {
    return this._rowStart;
}

get totalRows(): number {
    return this._totalRows;
}

private pageChange(pageParams: PageParams) {
    this._rowStart = pageParams.start;
    this._rowsPerPage = pageParams.pageSize;

    this.loadLog();
}

private loadLog() {
    let logs: Log[] = new Array();

    this._totalRows = logs.length;

    // so that pagination does not damaged when totalRows are less than rowsPerPage
    if (logs.length < 34) {
        this._rowsPerPage = logs.length;
    } else {
        this._rowsPerPage = 34;
    }

    this.displayArray.forEach((row, index, array) => {
        array[index] = logs[index + this._rowStart - 1];
    });
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.