The ngAfterViewInit lifecycle hook does not get triggered when placed within ng-content

The ngAfterViewInit lifecycle hook isn't triggered for a Component that is transcluded into another component using <ng-content>, as shown below:

<app-container [showContent]="showContentContainer">
    <app-input></app-input>
</app-container>

However, everything works fine without <ng-content>:

<app-input *ngIf="showContent"></app-input>

The container component is described as:

@Component({
  selector: 'app-container',
  template: `
        <ng-container *ngIf="showContent">
              <ng-content></ng-content>
        </ng-container>
  `
})
export class AppContainerComponent {
  @Input()
  showContentContainer = false;

  @Input()
  showContent = false;
}

The input component is defined as:

@Component({
  selector: 'app-input',
  template: `<input type=text #inputElem />`
})
export class AppInputComponent implements AfterViewInit {
  @ViewChild("inputElem")
  inputElem: ElementRef<HTMLInputElement>;

  ngAfterViewInit() {
    console.info("ngAfterViewInit has been executed!");
    this.inputElem.nativeElement.focus();
  }
}

Check out a live example here: https://stackblitz.com/edit/angular-playground-vqhjuh

Answer №1

There are a couple of key issues to address in this situation:

  1. Child components are created when the parent component is instantiated, not when <ng-content> includes them (refer to https://github.com/angular/angular/issues/13921)
  2. ngAfterViewInit does not signify that the component has been added to the DOM, only that the view has been initialized (check out https://github.com/angular/angular/issues/13925)

To solve this problem, one could address either or both of these issues:

  1. Rewrite the container directive as a structural directive to create content only when necessary. An example can be found here: https://stackblitz.com/edit/angular-playground-mrcokp
  2. Rework the input directive to respond to being actually attached to the DOM. One approach is to create a directive for this purpose. See an example here: https://stackblitz.com/edit/angular-playground-sthnbr

In many scenarios, it might be beneficial to tackle both of these aspects.

Nevertheless, dealing with option #2 can be simplified with a custom directive, which I will provide here for completeness:

@Directive({
    selector: "[attachedToDom],[detachedFromDom]"
})
export class AppDomAttachedDirective implements AfterViewChecked, OnDestroy {
  @Output()
  attachedToDom = new EventEmitter();

  @Output()
  detachedFromDom = new EventEmitter();

  constructor(
    private elemRef: ElementRef<HTMLElement>
  ) { }

  private wasAttached = false;

  private update() {
    const isAttached = document.contains(this.elemRef.nativeElement);

    if (this.wasAttached !== isAttached) {
      this.wasAttached = isAttached;

      if (isAttached) {
        this.attachedToDom.emit();
      } else {
        this.detachedFromDom.emit();
      }
    }
  }

    ngAfterViewChecked() { this.update(); }
  ngOnDestroy() { this.update(); }
}

It can be used like this:

<input type=text 
       (attachedToDom)="inputElem.focus()"
       #inputElem />

Answer №2

Upon reviewing the console in your stackblitz, it becomes evident that the event is triggered even before any button is pressed. It seems that everything defined as <app-container> will be initialized or constructed at the point of declaration.

In the example provided, if you insert a test function within the app-container, it will be executed immediately. This means that <app-input> will also be constructed without delay. Since ngAfterViewInit is only called once according to Angular's lifecycle hooks (source: https://angular.io/guide/lifecycle-hooks), this initial call occurs at this stage.

It is worth noting that including the following code snippet inside the AppInputComponent may seem unconventional:

ngOnDestroy() {
    console.log('destroy')
}

This would result in the component being immediately destroyed and not initialized again (you can confirm by adding constructor or ngOnInit logs).

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

Adding data from a database into an object in PHP for temporary use during the loading process can be achieved by following

I'm a beginner in PHP and I have some code that retrieves category type data from a database. I want to temporarily store this data in a PHP object while the page is loading. Initially, I need to load all predefined data and then use it when a certain ...

Updating a JavaScript global variable within a click event function: A quick guide

I am currently using Javascript and jQuery to retrieve the mouse coordinates of a click event for use in other Javascript functions. The issue I am facing is that global variables set within an event function do not update outside the function, unlike glob ...

Next.js deployments on Vercel are encountering issues with resolving local fonts

Currently, I am facing an issue while trying to incorporate next/fonts into my project in next.js 13.3. The setup works perfectly on my local machine, but as soon as I deploy it to Vercel, a build error arises with the message Module not found: Can't ...

Using AngularJS to bind to the 'src' property of an <img> tag

There is a table on my website with numerous rows, and each row contains a preview image that should appear in the top right corner when the mouse hovers over it. I attempted to insert an image tag with AngularJS binding for the URL in the src attribute l ...

Using PHP to ascertain the requested dataType or responseType from the client

My ajax request is fairly simple: $.post('server.php',data, function (json) {console.log(json)},'json'); I have configured jQuery to expect json data based on the dataType setting. Question: Is the dataType parameter equivalent to re ...

Discover how TypeScript's strictNullChecks feature can help you identify null values with ease in your functions

Since Javascript often requires me to check if a value is `!= null && != ''`, I decided to create a function that checks for empty values: const isEmpty = (variable: any, allowEmptyString?: boolean): boolean => { return variable == null | ...

Incorporate an array into a JSON object using AngularJS

I'm attempting to append a JSON array to a JSON object. Here's my code: $scope.packageElement = { "settings": [ { "showNextPallet": true, "isParcelData": false, "isFreightData": true, " ...

A guide to accurately fetching the transform properties of an SVG element within a d3.transition

Currently, I am experimenting with d3 animations using d3.transitions specifically involving circles. Consider the circle animation example below (d3.transition()): animationTime = 500; svg = d3.select('#svg'); // Locate th ...

Displaying content on the <div> element

Looking for recommendations for a jQuery plugin or JavaScript solution that allows me to load a full "view" into a <div> when a user clicks on a link. The challenge I'm facing is that I have 8 pages, with the Homepage consisting of 3 divisions: ...

Remove any errors as soon as the input field becomes valid

My current setup involves AngularJS with node.js. To handle errors, I have devised the following strategy: node router effect.js: router.post('/', function(req, res, next){ req.checkBody('name', 'Eff ...

Differences between Array and Database Search

Currently, I have implemented a system where I store a refresh token in a JavaScript array as well as in each user's information table. When a user requests data, I first check the token in the array. If the token matches one in the array, I loop thro ...

Sending data from a partial view to a controller

Imagine I have two models: DailyTasks and Task. The initial view is strongly typed with the DailyTasks model, displaying a list of existing tasks for the day. Users can add more tasks to the list/table by clicking the add button. Upon clicking the add butt ...

Steer clear of directly accessing views in AngularJS using angular-ui-router

In my AngularJS App setup, I have the following configuration: angular .module('MyApp') .config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvi ...

Utilize a vanilla JavaScript object as the primary model in Ember

Can a plain JS object, such as a literal object, be used as a model in EmberJS? I've noticed that all the examples in the documentation utilize Ember.Object or a datastore. I understand that I may not have access to features like observables with pl ...

The Angular Library seems to be malfunctioning as it does not execute the ngOnInit

I've been following the instructions from Angular CLI 6 to create a library, which can be found here. So far, I've successfully created and built my library. It includes a Component that I'm using for the UI and has an HTML selector. @Compo ...

Tips for inserting a line break within the output of an Angular pipe

Is there a way to display dates on separate lines in an Angular pipe? <th>{{(date | date: 'EEE MMM d')}}</th> Currently, the output is displayed like Mon Jul 20 - all in the same line. But I want it to be displayed like: Mon Jul ...

Monitoring and recording Ajax requests, and retrying them if they were unsuccessful

As a newcomer to Javascript, I'm diving into the world of userscripts with the goal of tracking all Ajax calls within a specific website. My objective is to automatically repeat any failed requests that do not return a status code of 200. The catch? T ...

Using a combination of look-arounds and tag omission for advanced parsing

I am trying to identify text that is not part of another word (which I have working successfully), but I also want to ensure that the text is not inside an <a> tag. "Java <li>Javascript</li> <a href="">Some Java here</a> more ...

Is the validation for the 'prop' property missing in props?

Seeking assistance with react's forwardRef feature. Currently encountering errors related to missing props validation in FadeContents. Is there a way to resolve this issue? It seems like the props need to be defined somewhere in order to be used withi ...

Using Javascript to access a website from a Windows Store application

Currently, I am working on a project to create a Windows store app using HTML and JavaScript. One of the key components of my app involves logging into a specific website with a username and password. Here is an example website for reference: The process ...