Skip to content

Angular ContentChildren

Angular Content Children Cover

After we mentioned ContentChild in the last post, we will move our focus onto ContentChildren, whose only difference is that instead of selecting only one element – it selects a QueryList of elements from the DOM.

(Wait, what is a QueryList? QueryList is an unmodifiable list of elements that Angular keeps track every time the state of the application changes. Both ContentChildren, and we will later see ViewChildren use QueryList to store elements from the DOM and content DOM. QueryList is an array-like data structure, and you guessed it, it has methods such as map, filter, find, forEach and others.).

When we use ContentChildren together with QueryList, any change within the QueryList is stored. Every time we add, remove or modify an item, the list itself will be updated and the observable bound to the query list will emit a new value. Like last time, we would use the ngAfterContentInit callback to set our content queries.

@ContentChildren

Let us start by copying the expiry element two more times inside our app.component.html file. Why would we do that – it could be tedious to create a ContentChild for every reference we might need. Three might still seem like a low, number but having a directive such as ngFor, well, let us just say, it could become very, very messy.

<app-user-card>
  <div class="more-data" fav-day>
    <h3>Favorite day:</h3>
    <p>Sunday</p>
  </div>
  <div class="more-data" dislikes>
    <h3>Dislikes:</h3>
    <p>The alarm clock</p>
  </div>
  <div class="more-data" expiry #expiry>
    <h3>Expiry Date:</h3>
    <p>20/05/2024</p>
  </div>
  <div class="more-data" expiry #expiry>
    <h3>Expiry Date:</h3>
    <p>20/05/2024</p>
  </div>
  <div class="more-data" expiry #expiry>
    <h3>Expiry Date:</h3>
    <p>20/05/2024</p>
  </div>
</app-user-card>

Nothing special, we just copy-pasted the last div element. Now we will also change the way we reference these elements inside our user-card.component.ts:

import {
  AfterContentInit,
  Component,
  ContentChildren,
  ElementRef,
  OnInit,
  QueryList,
} from '@angular/core';

@Component({
  selector: 'app-user-card',
  templateUrl: './user-card.component.html',
  styleUrls: ['./user-card.component.css'],
})
export class UserCardComponent implements OnInit, AfterContentInit {
  @ContentChildren('expiry') expiryReferences: QueryList<ElementRef>;

  constructor() {}

  ngOnInit() {}

  ngAfterContentInit() {
    console.log(this.expiryReferences);
  }
}

We changed the property decorator from ContentChild to ContentChildren, and we used QueryList with the type of ElementRef in order to create the expiryReference list. Again, we are using a simple reference of an element, but we also have the freedom to use selectors for @Component and @Directive, a token reference or a template reference. The result of the console.log() can be seen below:

ContentChildren – content of expiryReferences variable

The first thing we notice is that we have three elements in the _results array. We can quickly access the first and last element using the first and last property, the dirty property tells us whether we changed something in our query list, we have the changes observable that notifies the user of any changes, and inside the prototype we can find the above-mentioned list of methods that we could use – get, map, filter, find, forEach, destroy and others.

And bam – we get the following result:

ContentChildren – result

Well, printing out the structure of the reference isn’t that interesting. Let us see how to for example, assign a certain background color to every second element. For that, we would need to change the content ngAfterContentInit to following:

  ngAfterContentInit() {
    let index = 0;
    for (let reference of this.expiryReferences) {
      if (index % 2 === 1) {
        reference.nativeElement.style.backgroundColor = 'blue';
      } else {
        reference.nativeElement.style.backgroundColor = 'red';
      }
      index++;
    }
  }

We are just iterating through the list of references we have and check whether the number is divisible by two. In one case we are just setting our background color to blue, otherwise to red. This would work not only for three elements, but for 10, 100, or any other number with a big amount of zeroes :).

ContentChildren – setting the background color to every second element

For the complete project, please look at the Stackblitz below:

Final Words

So, when to use ContentChildren. Simply, if we see the need for ContentChild (projecting content), but at the same time realize that we might need to have multiple elements AND we might need a data structure to keep track of them. In that case, look no further than ContentChildren.

For more articles please click below, or check the blog.