The interconnectivity between ngAfterViewInit in Angular's LifeCycle and observables

enable.service.ts

@Injectable({
  providedIn: 'root'
})
export class EnableService {
  isEnabled$ = from(this.client.init()).pipe(
    switchMap(() => this.client.getEnabled()),
    map(([enabled, isAdmin]) => ({enabled: true, isAdmin: false})),
    share()
  ); // The observable returns enable and isAdmin values

  constructor(
    // Some constructor
  ) {}
}

main.component.ts

export class MainComponent implements OnInit, AfterViewInit, OnDestroy {
  @ViewChild('mymap') containerRef: ElementRef<HTMLDivElement>;

  isAdmin: boolean = false;
  isEnable: boolean = false;

  constructor(
    private enableService: EnableService,
  ) {
    this.enableService.isEnabled$.subscribe(res => {this.enable = res.enabled; this.isAdmin = res.isAdmin});
  }

  async ngAfterViewInit(): Promise<void> {
    // A hack to wait for the enableService subscription to get the actual value, otherwise containerRef #mymap may not exist
    await new Promise(resolve => setTimeout(resolve, 1000));

    // Execute third party sdk initialization only if containerRef exists
    if (this.containerRef) {
      // Third party SDK initialization code here
    }
  }

main.component.html

<div #mymap *ngIf="!isEnable || isAdmin"></div>

This code currently works with a 1-second delay in ngAfterViewInit. However, what if the enableService takes longer to retrieve the value? It could potentially break the functionality.

Is there a way to ensure that ngAfterViewInit is executed after the enableService retrieves the value?

Or perhaps there is a better approach that avoids using the 1-second delay. Setting the initial value of isEnable to false and then changing it to true could cause issues, similarly setting it to true when it's already true might cause errors. Moving the observable subscription from the constructor to ngOnInit did not solve the issue.

Answer №1

Is this effective?

Add a nested component within the NgIf directive to ensure that the ngOnInit lifecycle hook is triggered after the *ngIf condition evaluates to true!

typescript

get isEnabled$ {
    return this.enableService.isEnabled$;
}

html

<div #mymap *ngIf="!(isEnabled$ | async).isEnable || (isEnabled$ | async).isAdmin">
    <child-component></child-component>
</div>

Answer №2

To enhance your containerRef, consider implementing a setter method:

private _containerRef: ElementRef<HTMLDivElement>; 

@ViewChild('mymap') set content(content: ElementRef) {
  this._containerRef = content;
  if (content) {            
    // Perform any necessary operations with the reference
   }
}

The setter function automatically captures all changes when an element appears or disappears, eliminating the need for manual synchronization through a service call.

Answer №3

When using EnableService, the client service calls for methods like init and getEnable may sometimes return expected responses with a slight delay. This delay is usually less than the 1-second timeout set in ngAfviewInit.

If the service takes longer than 1 second to respond, the HTML content might not receive the necessary data on time, resulting in the issue you are currently facing.

While utilizing async pipes for data binding in your HTML is a recommended approach, there is another method that requires minimal code modifications:

In the main.component.ts file:

export class MainComponent implements OnInit, AfterViewInit, OnDestroy {
  @ViewChild('mymap') containerRef: ElementRef<HTMLDivElement>;

  isAdmin: boolean = false;
  isEnable: boolean = false;
  enableServiceCalled: boolean = false;

  constructor(
   private enableService: EnableService,
  ) {
   this.enableService.isEnabled$.subscribe(res => { 
   this.isEnable = res.enabled; 
   this.isAdmin = res.isAdmin;
   this.enableServiceCalled = true;
  });
  }

  async ngAfterViewInit(): Promise<void> {
    if (this.containerRef) {
     // Code execution based on the existence of containerRef
     }
    }
   }

In the main.component.html file:

<div #mymap *ngIf="enableServiceCalled && (!isEnable || isAdmin)"></div>

By using the enableServiceCalled boolean, you ensure that the required data is already available for use in your HTML elements. This solution aims to address your current challenge effectively.

Hopefully, this explanation proves helpful to you.

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

Employing Modernizer.js to automatically redirect users to a compatible page if drag and drop functionality is not supported

I recently set up modernizer.js to check if a page supports drag and drop functionality. Initially, I had it set up so that one div would display if drag and drop was supported, and another div would show if it wasn't. However, I ran into issues with ...

Replacing a div with another div can be achieved in a single swap

My goal is to swap one div with another div upon clicking using the provided code. It functions properly for a single instance. However, the issue arises when the class appears multiple times, causing all instances to change due to sharing the same class n ...

Is there a way to set up gulp without relying on npm when using shared hosting?

While working on my shared hosting, I encountered a roadblock regarding the installation of gulp for compiling LESS assets into CSS. The hosting administrator has declined to install npm, which is essential for setting up gulp. Given this limitation, I am ...

Implementing Facebook Javascript SDK to enable login and trigger re-authentication using React Web and Typescript within a component

As a newcomer to stack overflow, I welcome any suggestions on how I can improve my question. I'm in need of guidance concerning logging a user into facebook and requiring them to authenticate their profile or select another profile manually, rather t ...

Transform the post data into a JSON string within the controller

Hello everyone, I have a sample table that I want to share: <table class="table table-bordered" width="100%" cellspacing="0" id="tableID"> <thead> <tr> <th>A</th> <th>B</th> <th>C< ...

React component experiencing double execution of SetTimeout function

Every time I render the App component, the code inside setTimeout seems to be running twice. I've noticed that setTimeout executes after the call stack is cleared. I wonder if this has any connection to the issue. Could it be related to how React ha ...

What steps can be taken to fix a syntax error in a NodeJS express server code?

I am currently facing a syntax error in the code below, and I'm struggling to fix it. The specific error message is as follows: node staticapi.js /Users/v/Desktop/CS-Extra/EIP/A5/staticapi.js:123 res.status(200).send("Api is running") ...

having trouble transferring data from one angular component to another

I've been attempting to send data from one component to another using the service file method. I've created two components - a login component and a home component. The goal is to pass data from the login component to the home component. In the l ...

Unraveling in jQuery

Struggling to properly handle the data being returned by JQuery from an API call. Currently encountering an error in the process. Is it possible to iterate through data using a JQuery loop like this? $.each(data.results, function (i, item) { // attemptin ...

Obtain information from a web address using Ionic framework

Hello, I am experiencing an issue with retrieving data from a URL in my Ionic application. When using @angular/http to fetch a JSON object from the URL, everything works fine in the browser when running 'ionic serve'. However, when deploying the ...

I encountered login issues when trying to access dist/index.html in my Angular 8 application, but I found a workaround by utilizing the proxy.conf.json file, which

I have been trying to login through the index.html page in the angular 8 dist folder, but I keep encountering an error with the login API URL. Despite spending two days on this issue, I have not been able to find a solution. If anyone has any suggestions o ...

What is the best method to find a matching property in one array from another?

I am working with two arrays in TypeScript. The first one is a products array containing objects with product names and IDs, like this: const products = [ { product: 'prod_aaa', name: 'Starter' }, { product: 'prod_bbb&apos ...

Is the NodeJS rmdir function experiencing issues specific to LINUX?

Currently, I have a NodeJS script section that runs on my Windows 10 machine with the latest Node version and another version on my CentOS8 Linux webserver. The code executes as expected on Windows but throws an error when running on Linux at this specific ...

Is there a way to automatically update the input value when I refresh the page following a click event?

Currently, I have multiple p elements that trigger the redo function upon being clicked. When a p element is clicked, the quest[q] template is loaded onto the .form div. These templates are essentially previously submitted forms that sent values to an obj ...

Adding dynamically fetched JSON to an existing table

http://jsfiddle.net/mplungjan/LPGeV/ What could be improved in my approach to accessing the response data more elegantly? $.post('/echo/json/',{ "json": JSON.stringify({ "rows": [ { "cell1":"row 2 cell 1", "cel ...

Guide on implementing a globalThis polyfill within a NextJS application

Having some trouble with the Mantine react component library on older iOS versions. It's throwing a ReferenceError: Can't find variable: globalThis I've looked into polyfills, but I'm struggling to figure out how to integrate it into ...

Tips for obtaining the rotation angle within the Ionic gesture API?

Currently, I am working on canvas and facing an issue while handling gesture events with Hammer.js. Despite seeking help in various forums, including this one, I have yet to receive a response. Now, I am trying my luck with Ionic gestures but struggling to ...

Can you help me identify the issue with my current Jade for loop implementation?

Here is my full loop code written in Jade: block content div(class='row') div(class='col-lg-12') h1(class='subject') 로또라이 div(class='row') div(class='col-lg-8') - for (var ...

Different ways to save data fetched from a fetch request

I'm fairly new to React and could use some assistance. I am trying to retrieve data from a movie database based on a search term. I have a method called getMovies where I utilize fetch to grab the data. The information is located in data.Search, but I ...

Refreshing HTTP request in Angular

I am currently working with Angular 5 and have encountered the following issue: Within my route, I have a parameter called year. The component related to this route is supposed to display data based on the year parameter, which is fetched from a service. ...