Understanding , , and

Tarun Sharma
Dec 24, 2017 · 7 min read

In user interface we can apply composition in a similar way. We can think of the individual component as functions. These functions can be composed together in order and as result we get more complex functions.

We can illustrate this graphically by the following structural diagram:

In the figure above we have two elements:

  • - A self-contained element which holds some logic, but does not contain any structure.
  • - An element, which specifies the element and holds a list of other instances (which could also be components since extends ).

This means that using the preceding abstractions we can build structures of the following form:

On the figure above we can see a hierarchical structure of components and directives. The leaf elements on the diagram are either directives or components that don’t hold references to other directives.

Composition of Components in Angular

Now, in order to be more specific, lets switch to the context of Angular.

In order to better illustrate the concepts we are going to explore, lets build a simple application:

// ...
@Component({
selector: 'todo-app',
template: `
<section>
Add todo:
<todo-input (todo)="addTodo($event)"></todo-input>
</section>
<section>
<h4 *ngIf="todos.getAll().length">Todo list</h4>
<todo-item *ngFor="let todo of todos.getAll()" [todo]="todo">
</todo>
</section>
<ng-content select="app-footer"></ng-content>
`
})
class TodoAppComponent {
constructor(private todos: TodoList) {}
addTodo(todo) {
this.todos.add(todo);
}
}
// ...

Yes, this is going to be “Yet another MV* todo application”. Above we define a component with selector which has an inline template, and defines a set of directives that it or any of its child components is going to use.

We can use the component in the following way:

<todo-app></todo-app>

Well, this is basically an XML, so between the opening and closing tags of the element we can put some content:

<todo-app>
<app-footer>
Yet another todo app!
</app-footer>

</todo-app>

Basic Content Projection with

Now lets switch back to the component’s definition for a second. Notice the last element in its template: . With we can grab the content between the opening and closing tag of the element and project it somewhere inside of the template!

The value of the attribute is a CSS selector, which allows us to select the content that we want to project. For instance, in the example above, the will be projected at the bottom of the rendered todo component.

We can also skip the attribute of the element. In this case we will project the entire content passed between the opening and closing tags on the place of the element. You can say this transclusion

There are two more components which are not interesting for our discussion so we are going to omit their implementation. Once completed our application will look as follows:

ViewChildren and ContentChildren

And yes, it was that easy! Now we are ready to define what the concepts of view children and content children are.

Content and View

  • *The children element which are located inside of its template of a component are called view children **
  • **elements which are used between the opening and closing tags of the host element of a given component are called content children **

its very much clear from this diagram <todo-input> and <todo-item> both are child of todo-app component so they will be considered as @ViewChildren

and app-footer declared inside<todo-app/> will be replaced with <ng-content/> definition

This means that and could be considered view children of , and (if it is defined as Angular component or directive) could be considered as a content child.

Accessing View and Content Children

Now comes the interesting part! Lets see how we can access and manipulate these two types of children!

Playing around with View Children

Angular provides the following property decorators in the package: , , and . We can use them the following way:

import {ViewChild, ViewChildren, Component, AfterViewInit...} from '@angular/core';// ...@Component({
selector: 'todo-app',
template: `...`
})
class TodoAppComponent implements AfterViewInit {
@ViewChild(TodoInputComponent) inputComponent: TodoInputComponent
@ViewChildren(TodoComponent) todoComponents: QueryList<TodoComponent>;
constructor(private todos: TodoList) {}
ngAfterViewInit() {
// available here
}
}
// ...

The example above shows how we can take advantage of and . Basically we can decorate a property and this way query the view of a component. In the example above, we query the child component with and with .

We use different decorators because we have different number of instances of the components that we want to select. For instance, we can select with because we have only a single instance of it, but we have multiple todo items, so for them we need to apply the decorator.

Another thing to notice are the types of the and properties. The first property is of type . It’s value can be either , if Angular haven’t found such child, or a reference to the instance of the component’s controller (in this case, reference to an instance of the class). On the other hand, since we have multiple instances which can be dynamically added and removed from the view, the type of the property is .

We can think of the as an observable collection, which can emit events once items are added or removed from it. We can access the wrapped by the with its property. For further information click here.

Since Angular’s DOM compiler will process the component before its children, during the instantiation the and properties will have value . Their values are going to be set in the life-cycle hook.

Accessing Content Children

Almost the same rules are valid for the element’s content children, however, there are some slight differences. In order to illustrate them better, lets take a look at the root component, which uses the :

@Component({
selector: 'app-footer',
template: '<ng-content></ng-content>'
})
class FooterComponent {}
@Component(...)
class TodoAppComponent {...}
@Component({
selector: 'demo-app',
styles: [
'todo-app { margin-top: 20px; margin-left: 20px; }'
],
template: `
<content>
<todo-app>
<app-footer>
<small>Yet another todo app!</small>
</app-footer>
</todo-app>
</content>
`
})
export class AppComponent {}

In the snippet above we define two more components and . visualizes all of the content passed between the opening and closing tags of its host element (). On the other hand, uses and passes between its opening and closing tags. So given our terminology from above, is a content child of . We can access it in the following way:

// ...
@Component(...)
class TodoAppComponent implements AfterContentInit {
@ContentChild(FooterComponent) footer: FooterComponent;
ngAfterContentInit() {
// this.footer now points to the instance of `FooterComponent`
}
}
// ...

As we can see from above, the only two differences between accessing view children and content children are the decorators and the life-cycle hooks in which they are initialized. For grabbing all the content children we should use (or if there’s only one child), and the children will be set on .

vs

Alright! We’re almost done with our journey! As final step lets see what the difference between and is (if you’re not familiar with the dependency injection mechanism of Angular.

Lets peek at the declaration of the :

class TodoList {
private todos: Todo[] = [];
add(todo: Todo) {} remove(todo: Todo) {} set(todo: Todo, index: number) {} get(index: number) {} getAll() {}
}
@Component({
// ...
viewProviders: [TodoList]
// ...
})
class TodoAppComponent {
constructor(private todos: TodoList) {}
// ...
}

Inside of the decorator we set the property to an array with a single element - the class. The class holds all the todo items, which are entered in the current session.

We inject the service in the ’s constructor, but we can also inject it in any other directive’s (or component) constructor, which is used in the ’s view. This means that is accessible from:

However, if we try to inject this service in ’s constructor we are going to get the following runtime error:

ORIGINAL EXCEPTION: No provider for TodoList!

This means that providers declared in given component with are accessible by the component itself and all of its view children.

In case we want to make the service available to as well we need to change the declaration of the component’s providers from to .

When to use ?

Why would I use , if such providers are not accessible by the content children of the component? Suppose you’re developing a third-part library, which internally uses some services. These services are part of the private API of the library and you don’t want to expose them to the users. If such private dependencies are registered with and the user passes content children to any of the components exported by the public API of your library, she will get access to them. However, if you use , the providers will not be accessible from the outside.

This is best reference i can find from Asim Hussain

Tarun Sharma

Written by

Developer 💻, Trainer 👨‍🏫, Publisher 📕 & Mentor 🗣 #JavaScript #ReactJs #GraphQL #NodeJs Publishing Videos Tutorials http://medium.co .Writing code at Srijan

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade