Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Angular Content projection with nested children

StackBlitz Eample is here

I have a component where I would like the user to define there own template and then I want to pass that template to some nested children. I’m having issues getting an instance of templates in the parent component.

I have my directive here

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@Directive({
  selector: '[customTemplate]',
})
export class CustomTemplate {
  public field!: string;

  constructor(public el: ElementRef) {}
}

I want to put this inside of a parent and get all instances of these directives.

<div customTemplate field="test1">
  <ng-template myTemplate>
    <P>Some text here T1</P>
  </ng-template>
</div>
<div customTemplate field="test2">
  <ng-template myTemplate>
    <P>Some text here T2</P>
  </ng-template>
</div>

<Child1>
  <Child2>I'm going to render the ng-templates of myTemplate here</Child2>
</Child1>

In my Parent Component I have this

    @Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewInit {
  @ContentChildren(CustomTemplate)
  public templates?: QueryList<CustomTemplate>;

  ngAfterViewInit(): void {
    console.log(this.templates);
    //here how do I get the instances of CustomTemplate
    
  }
}

The QueryList is empty
enter image description here

>Solution :

I believe that content children might not be the right call. Using ViewChildren results in them being discovered. However, a few modifications need to be made.

Your selector in your directive is set as [customTemplate]. This is fine, however the selectors are case sensitive. Thus in your HTML when you use it as CustomTemplate it won’t be discovered. Thus change your HTML to be either customTemplate or update your selector to have a capital C.

Secondly, in order to do anything of value with said ViewChildren, as is mentioned here (@ViewChildren Querylist Array is empty when children are rendered with *ngFor) you need to subscribe to any changes that occur in your AfterViewInit

ex:

this.templates.changes.subscribe((x) => console.log("From Change Sub: ", x));

Lastly, instead of trying to find the children using a string literal, pass in the actual class name instead as so:

@ViewChildren(CustomTemplate) instead of @ViewChildren('CustomTemplate') or @ViewChildren('customTemplate')

The latter two do not work, the first one does. Also with the first one if you ever do decide to change the name of the class it will propagate throughout the app, and anywhere it did not the typechecker will find it.

Updated stackblitz https://stackblitz.com/edit/angular-z5a8ae?file=src/app/app.component.html

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading