Obtaining the HTML element through ViewChild once the ngIf condition is met

I'm struggling with accessing my canvas element when its *ngIf condition is met. Let me provide some context to explain the issue.

In my application, there's a canvas element (initially hidden) and a ViewChild element ref variable in my typescript file that accesses the canvas. However, because the canvas isn't rendered initially, the ViewChild element ref variable remains undefined. When the ngIf condition becomes true, the canvas is finally rendered but the ViewChild element ref variable isn't updated accordingly. In the code snippet below, a floor plan is loaded from a database when selected by the user. The canvas will only be displayed once the floor plan is chosen (not null).

How can I make sure that the ViewChild element ref variable recognizes when the canvas is loaded so it's not undefined when attempting to use the canvas?

<div class="row" style="padding-left: 3rem;" *ngIf="floorPlan != null">
    <div class="col-lg-6 col-xl-6 col-md-12 col-sm-12" style="text-align: center;">
        <canvas (click)="onCanvasClick($event)" style="border: 1px solid lightgray;" #fpCanvas [ngClass]="{over: over}">
        </canvas> 
    </div>
</div>
@Component({
  selector: 'app-floor-plan',
  templateUrl: './floor-plan.component.html',
  styleUrls: ['./floor-plan.component.css']
})
export class FloorPlanComponent implements OnInit, AfterViewInit, AfterViewChecked {

  floorPlan: FloorPlan = null;
  imagePath : string = "";

  @ViewChild('fpCanvas', { static: true }) fpCanvas: ElementRef<HTMLCanvasElement>;

    ....


  constructor(private dataBaseManager: DatabaseManagerService) {
    this.dataBaseManager.loadedFloorPlanSubject.subscribe(loaded => {
      this.floorPlan = new FloorPlan(loaded);
      setTimeout(this.initCanvasAndContext, 2000)
      this._image.src = this.floorPlan.getImagePath();

    })


   ....

 chooseFloorPlan() {

    this.onToggleChooseFloorPlanDialog();
    this.dataBaseManager.fetchFloorPlan(this.selectedFloorPlanIndex)

  }




}

Answer №1

This solution is specifically for Angular 8 and higher versions

To begin, modify static: true to static: false

@ViewChild('fpCanvas', { static: false}) fpCanvas: ElementRef<HTMLCanvasElement>;

Utilize ChangeDetectorRef to manually detect changes whenever the floorPlan gets updated.

this.floorPlan = new FloorPlan(loaded);
this.changeDetectorRef.detectChanges();

It's important to note that placing asynchronous logic within the constructor is not recommended.

It is advisable to move it to the ngOnInit method.

ngOnInit() {
    this.dataBaseManager.loadedFloorPlanSubject.subscribe(loaded => {
      this.floorPlan = new FloorPlan(loaded);
      this.changeDetectorRef.detectChanges();
      setTimeout(this.initCanvasAndContext, 2000)
      this._image.src = this.floorPlan.getImagePath();
    })
}

For more information, please check the related thread provided in the comments.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Receiving an error response from the server upon subscribing to an Angular service (2/4/5/6)

I'm currently facing an issue with verifying my OTP. Depending on the response received from the server (whether it's due to OTP mismatch or OTP expiration), I need to display the appropriate error message. However, I am struggling to figure out ...

Issue encountered while implementing a recursive type within a function

I've created a type that recursively extracts indices from nested objects and organizes them into a flat, strongly-typed tuple as shown below: type NestedRecord = Record<string, any> type RecursiveGetIndex< TRecord extends NestedRecord, ...

Supabase's edge function is being executed twice, despite only one call being made

I am facing an issue with my edge function in TypeScript at Supabase that connects to our Postgres database and runs a query. The problem is that the function is being executed twice, regardless of whether I run it locally in the CLI or deploy it to produc ...

Upon updating my Angular application from version 5.2 to the most recent one, I encountered an ERROR when running ng build

There was an error in the file ./src/styles.css (./node_modules/@angular-devkit/build-angular/src/angular-cli-files/plugins/raw-css-loader.js!./node_modules/postcss-loader/src??embedded!./src/styles.css) The module build failed due to a SyntaxError (60: ...

Issue with TypeScript: Rxjs uses different syntax for setTimeout compared to what is defined in @types/node

System Information: Node version: v11.7.0 RxJS version: 6.3.3 @types/node version: 8.10.45 tsc version: 3.2.4 During the execution of tsc, it appears that there is an issue within Rxjs where the setTimeout function is being called without specifying th ...

Is there a way to reverse the distributive property of a union in TypeScript?

Looking at the following code snippet, what type should SomeMagic be in order to reverse the distributiveness of Y? type X<A> = { value: A }; type Y = X<number> | X<string>; type Z = SomeMagic<Y>; // <-- What type should Some ...

Indicate the initial position of the scroll bar

Currently, I am working on implementing scrolling functionality and attempting to start it at a specific element based on a given id. This is how my html code looks like: <div class="list-wrapper" style="max-height:350px;overflow-y:scroll" > < ...

What is the best way to authenticate an admin in the front-end using backend technologies like Node.js, Angular, and MongoDB?

Within the user model, there is a property named isAdmin with a default value of false. In MongoDB, I have manually created an admin account with the isAdmin property set to true. When logging in as an admin, the program verifies this and displays "admin ...

Ways to manage multiple Observables

Two Observables are being returned from different services, each providing only one value (similar to Observable.just()). In TypeScript, types play a crucial role in this context. Is there a method to determine when both Observables have been resolved (in ...

Enter a single unidentified character

As someone new to TypeScript, I have a question regarding my code. I am converting TypeScript into JavaScript to run in an environment where the window object has additional functions that I have declared on the TypeScript side like this: interface Window ...

Issue occurred when trying to load controllers during the migration process from AngularJS1 to Angular6

Currently, I am in the process of upgrading AngularJS1 components to Angular6. My strategy involves creating wrappers for all existing AngularJS1 components by extending "UpgradeComponent" and storing them under the folder "directive-wrappers". However, wh ...

What is the best way to transform all elements on a webpage into a dynamic scrolling marquee?

Is there a way to make every div in a web application scroll like a marquee? Perhaps by using a specific CSS class or other method? The application is built with Angular 4 and Bootstrap. ...

The third version of Angular 2's router, known as

Attempting to implement the new v3 router proved challenging. After updating my package.json to reference the alpha version and installing it, I encountered a recurring error... node_modules/@angular/router/router.d.ts(80,59): error TS2304: Cannot find na ...

The issue with Angular 2's Parameterised router link component not fully refreshing

I'm trying to figure out how to show a set of images when I click on a specific menu item. The menu structure looks like this: <ul id="demo23" class="collapse"> <li> <a [routerLink]="['image-gallery','Picasso ...

Generate a collection of items through replication

Develop a function that takes specific input and generates an array of objects with a length of 10 by incrementing the ID of each duplicate object. The first object in the output array should have "visible" set to true, while all others should have it set ...

I can't see the title text on my Ionic button, what should I do to fix this issue?

I have been working on a login form using ngx-translate and all components are translating correctly except for the submit button. It seems that the translated text for the button does not display unless it is hardcoded or clicked on. I'm not sure if ...

Unable to determine all parameters for the ViewController: (?, ?, ?)

During my work on a project using IONIC 3 and Angular 4, I encountered the need to create a component responsible for managing popover controllers. Transferring data from this component to the popover component was straightforward. However, I ran into an i ...

What could be causing Angular to not show the outcome? Why is it that only the complete-handler is being triggered?

Just wanted to share my current setup: ASP.NET Core 8 Web API .NET Core 8 backend for frontend Angular SPA served inside a bff using typescript (ES2022) Request flow: -> SPA (Cookie) -> BFF (Token) -> API Struggling with the SPA to display or i ...

Excluding a Lazy Loaded Module from Production Build in Angular

For demonstration purposes, I have an angular module called DevShowcaseModule. However, it is crucial that this module is not included in the production build to prevent demo code errors and keep it hidden from end users. Details: Angular Version: 7.2.5 ...

What specific type of useRef should I use to reference a callback function?

I have been exploring the method outlined by Dan Abramov for creating a custom hook to handle basic setInterval functionality. However, I am facing challenges while trying to type it in TypeScript. Specifically, I am unsure about what should be the type of ...