0

In my angular-7 project, I am trying to make an html page with nested material tabs where in second tab will have another set of tabs. In second tab, trying to make canvas chart for data passed to child component.

Here is my html code.

<mat-tab-group mat-stretch-tabs [selectedIndex]="0">
    <mat-tab label="Sales"> Sales            
    </mat-tab>

    <mat-tab label="Purchase">
        <!-- <ng-template matTabContent>               //This block works but i want in tab format
            <div *ngIf="isReady " class="divinput ">
                <div *ngFor="let d of data">
                    <draw [input]="d "></draw>
                </div>
            </div>
        </ng-template> -->

        <mat-tab-group *ngIf="isReady">                   // this throws error
            <mat-tab *ngIf="isReady" label="north">
                <ng-template matTabContent>
                    <div *ngFor="let d of data">
                        <draw [input]="d"></draw>
                    </div>
                </ng-template>
            </mat-tab>
        </mat-tab-group>

    </mat-tab>
</mat-tab-group>

The above code calls a child component "draw" which has function to draw chart.

private draw (chart){ 
    var canvas = <HTMLCanvasElement> document.getElementById(chart.id);
    var ctx = canvas.getContext("2d");
    return new Chart(ctx, {
        type: 'line',
        data: {labels: chart.x,datasets: mydata}
    }) 
}

this throws error , TypeError: Cannot read property 'getContext' of null for line var ctx = canvas.getContext("2d"); in function draw. It looks like material-tabs does not wait for data to be available. I tried to handle this by "isReady" but no luck.

One strange thing i noticed that, it works when I change [selectedIndex]="0" to [selectedIndex]="1" . But can not consider this as first tab should be active on load as per requirement.

I struggling hard to figure out the problem. Please help to resolve the issue.

3
  • did you call draw (chart) before to set isReady = true? Commented May 17, 2020 at 19:00
  • draw(chart) if from child component and isReady is setting in parent component and sending to child. Commented May 17, 2020 at 19:43
  • Forget all the is ready garbage. Just use view child and make sure to not call draw in your component till the after view init hook Commented May 17, 2020 at 20:28

1 Answer 1

1

in angular specifically you can use ViewChild instead of getElementById to get canvas

in angular 7 specifically it will work as follow

example

component.html

<canvas #chart></canvas>

component.ts

    import { Component, OnInit, ViewChild, ElementRef, Input } from '@angular/core';

    @Component({
      selector: 'app-draw',
      templateUrl: './draw.component.html',
      styleUrls: ['./draw.component.css']
    })
    export class DrawComponent implements OnInit {

      @ViewChild('chart')
      chartElementRef: ElementRef<HTMLCanvasElement>;

      @Input()
      input: any;

      constructor() { }

      ngOnInit() {
        this.draw();
      }

      private draw () { 
        const canvas = this.chartElementRef.nativeElement;
        const ctx = canvas.getContext("2d");
      }
    }
Sign up to request clarification or add additional context in comments.

15 Comments

This will fail. View children aren’t available till the after view init hook
@bryan60 not true, in my example canvas itself not under ngIf, so ViewChild will set it before ngOnInit
this is a less common circumstance where it works... best practice is not accessing ViewChild(ren) until the AfterViewInit hook. That's when it's guaranteed: angular.io/api/core/ViewChild#description and here: angular.io/guide/lifecycle-hooks#afterview
this also only even working cause your blitz is angular 7 which only provided static queries. 8+ defaults to dynamic queries and would require you to explicitly set static to true.. i don't see why you'd code in a way that can break with upgrades when you can just use the afterViewinit hook
@bryan60 it works because canvas not angular component and not in component lifecycle, it is intended to how it used. some one try to claim it as a bug but angular team add static property instead github.com/angular/angular/issues/21800#issuecomment-360799520
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.