Soufiane Boutahlil
Soufiane Boutahlil

Reputation: 2604

ERROR TypeError: Cannot read property 'nativeElement' of undefined because of ng-template

I'm using Angular 7 and I have a problem with ng-template, I can't get canvas reference because canvas inside ng-template, and I can't change ng-template with something because I'm using ngbModal. How can I access to canvas? Thank you

This is the error:

Error: Cannot read property 'nativeElement' of undefined

Typescript:

import { Component, ViewChild } from "@angular/core";
import { NgbModal, ModalDismissReasons } from "@ng-bootstrap/ng-bootstrap";

@Component({
  selector: "ngbd-modal-basic",
  templateUrl: "./modal-basic.html"
})
export class NgbdModalBasic {

  @ViewChild("canvasComm") canvas; //I declared canvas here
  closeResult: string;
  imgloaded: boolean = false;
  img_user;

  constructor(private modalService: NgbModal) {}

  open(content) {
    this.modalService
      .open(content, { ariaLabelledBy: "modal-basic-title" })
      .result.then(
        result => {
          this.closeResult = `Closed with: ${result}`;
        },
        reason => {
          this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
        }
      );
  }

  uploadImg(event: any): void {
    var file = event.target.files[0];
    const extension = file.name.split(".")[1].toLowerCase();
    const size = file.size / 1024 / 1024;
    this.imgloaded = true;
    let canvas = this.canvas.nativeElement; //the problem in this line, canvas is null
    let context = canvas.getContext("2d");

    var render = new FileReader();
    render.onload = () => {
      var img = new Image();
      img.onload = () => {
        var hRatio = canvas.width / img.width;
        var vRatio = canvas.height / img.height;
        var ratio = Math.min(hRatio, vRatio);
        var centerShift_x = (canvas.width - img.width * ratio) / 2;
        var centerShift_y = (canvas.height - img.height * ratio) / 2;
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.drawImage(
          img,
          0,
          0,
          img.width,
          img.height,
          centerShift_x,
          centerShift_y,
          img.width * ratio,
          img.height * ratio
        );
      };
      let csv: string = render.result as string;
      img.src = csv;
    };
    this.img_user = event.target.files[0];
    render.readAsDataURL(event.target.files[0]);
  }

  private getDismissReason(reason: any): string {
    if (reason === ModalDismissReasons.ESC) {
      return "by pressing ESC";
    } else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
      return "by clicking on a backdrop";
    } else {
      return `with: ${reason}`;
    }
  }
}

template

<ng-template #content let-modal>
  <!-- ng-template is the problem -->
  <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">Profile update</h4>
    <button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <div>
      <div class=" box-grid">
        <span class="bull ">Photo</span>
      </div>
      <div class="border-formeDoc  Shadow" style="padding: 0;">
        <div class="profile-img">
          <!-- canvas is here -->
          <canvas width="120" height="120" id="canvasComm" #canvasComm [hidden]="!imgloaded" style="    border-radius: 50%;     
                      background-color: white;"></canvas>
          <img src="/assets/icons/iconcommercial.png" alt="" *ngIf="!imgloaded" style="filter: grayscale(1);" />
          <div class="file btn btn-lg btn-primary">
            <input accept=".png,.jpg,jpeg" type="file" (change)="uploadImg($event)" name="file" />
          </div>
        </div>
      </div>
    </div>
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-outline-dark" (click)="modal.close('Save click')">Save</button>
  </div>
</ng-template>

<button class="btn btn-lg btn-outline-primary" (click)="open(content)">Launch demo modal</button>

<hr>

<pre>{{closeResult}}</pre>

Upvotes: 1

Views: 1604

Answers (3)

uminder
uminder

Reputation: 26190

In your template, you defined the reference variable #canvasComm inside the canvas element. This same variable name must be used with @ViewChild to make it work.

export class NgbdModalBasic {

  @ViewChild("canvasComm") canvas;

UPDATE

If this still doesn't work, you can try to get rid of @ViewChild and access your canvas element using document.getElementById instead.

let canvas = document.getElementById("canvasComm");

Upvotes: 1

Amey
Amey

Reputation: 815

Angular 8

@ViewChild("canvasComm",{statics:false}) canvas ;

Angular 7 @ViewChild("canvasComm") canvas ;

use this

Upvotes: 0

Adrita Sharma
Adrita Sharma

Reputation: 22203

As a workaround, you can try this:

.html

<canvas width="120" height="120" id="canvasComm" #canvasComm [hidden]="!imgloaded" style="    border-radius: 50%;     
                      background-color: white;"></canvas>

 <input accept=".png,.jpg,jpeg" type="file" (change)="uploadImg($event, canvasComm )" name="file" />

.ts

 uploadImg(event: any, canvas:any): void {
 }

Upvotes: 1

Related Questions