Search code examples
angulartypescriptviewchild

How to avoid TypeError in angular?


In the .ts file I have :-

    @Component({
      selector: 'stl-app',
      templateUrl: './stl-app.component.html',
      styleUrls: ['./stl-app.component.scss']
    })
    export class ImlStlAppComponent implements OnChanges {
    
      @Input()
      filename: string;
      @Input()
      colorname: any;
      @Input()
      perspective: number;
    
      private scene: Scene;
      private camera: PerspectiveCamera;
      private renderer: WebGLRenderer;
      @ViewChild("myCanvas") myCanvas: any;
    
      constructor(private render: Renderer2,private sanitizer: DomSanitizer) {
      }
    
      ngOnInit(): void {
        //add listener for the resize of the window - will resize the renderer to fit the window
        let global = this.render.listen('window', 'resize', (evt) => {
          this.onWindowResize();
        })
      }
    
      ngOnChanges(changes: SimpleChanges) {
        this.mySubmit();
      }
    
      mySubmit() {
       
        //renderer
        this.renderer = new WebGLRenderer({ alpha: true, canvas: this.myCanvas.nativeElement});
        this.renderer.setSize(this.width, this.height);
    
       //Set scene, camera,lights etc
    
        })
    
        //request animation
        this.animate(this.controls);
    
      }
    
//will resize the renderer and the camera to the right size of the window

      onWindowResize() {
    }
    }

In the .html file I have :-

    <div style="text-align:center">
          <canvas #myCanvas id="myCanvas">
          </canvas>
        </div>

*Error in the console is the following :- "core.js:4197 ERROR TypeError: Cannot read property 'nativeElement' of undefined at StlAppComponent.mySubmit (stl-app.component.ts:59) and at StlAppComponent.ngOnChanges (stl-app.component.ts:51)"

How to avoid this 'nativeElement' problem ? and what is the reason behind this error?*


Solution

  • Angular's lifecycle hook ngOnChanges gets executed first before the component template is rendered, which means that your @ViewChild myCanvas is still not initialized by Angular, it will only have a value after the view has been initialized.

    Here is a documentation on the order of Angular Components Lifecycle Hooks order : https://angular.io/guide/lifecycle-hooks#lifecycle-event-sequence

    A quick fix would be to surround submit() call by a value check like this

          ngOnChanges(changes: SimpleChanges) {
            if(this.myCanvas) {
              this.mySubmit();
            }
          }
    

    And you can use the ngAfterViewInit() hook if you want something to get executed as soon as your view gets initialized (And you get a value in your myCanvas)