Components
File Structure
Components have some default filenames:
<component-name>.component.html
: An HTML template of what will be rendered on the page.<component-name>.component.ts
: Typescript file to define behavior.<component-name>.component.css
: File with component specific CSS.<component-name>.component.spec.ts
: File with the component's tests.
Additional Options (Flags)
--prefix <prefix-name>
To auto configure a custom prefix for the Component, instead of app
--export <boolean>
The declaring NgModule exports this component
--inline-template <boolean>
To not create HTML file, and use inline template
--inline-style <boolean>
To not create CSS file, and uyse inline style
--standalone <boolean>
To create the component as standalone
--type <type-name>
To add new <component-name>.<type-name>.ts
file with specified type-name
Best Practices
Perform complex initializations outside of the constructor.
Components should be cheap and safe to construct.
You should not, for instance, fetch data in a component constructor.
A good place for complex or async logic is in
ngOnInit
.
Set up the component after Angular sets the input properties.
Constructors should do no more than set initial local variables to simple values.
Keep in mind that a directive's data-bound input properties are not set until after construction.
If your need to initialize the directive based on those properties, set them on
ngOnInit
.
Cleaning up on instance destruction.
You can put clean up logic in
ngOnDestroy
, the logic that must run before Angular destroys the directive.Free resources that won't be garbage-collected automatically like:
Unsubscribe from Observables and DOM events.
Stop interval timers.
Unregister all callbacks that the directive registered with global or application services.
Prefer decorating
@Input
and@Output
overgetters
andsetters
, and avoid using aliases on them.Delegate complex logics to
Services
.
Code Structure
By default, a component's styles only affect elements defined in that component's template.
It is optional to write template and styles in separate files.
Angular creates an instance of the component for every matching HTML element it encounters.
@Component
decorator
@Component
decoratorCreating the Component Selector
Selector
Every Component defines a CSS Selector
that determines how the component is used.
Angular matches selectors statically at compile-time.
An element can match exactly one component selector.
Component selectors are case-sensitive.
When prefixing the name of a selector, NEVER use the prefix ng
. (As they may conflict with Angulars own ones)
Declare a Component with one of 3 types of selectors:
Type Selector
Matches elements based on their HTML tag name, or node name
profile-photo
Attribute Selector
Matches elements based on the presence of an HTML attribute and, optionally, an exact value for that attribute
[dropzone]
[type="reset"]
Class Selector
Matches elements based on the presence of CSS class
.menu-item
You should take advantage of the type of selector to choose depending on the type of Component you are building.
For instance:
Use a
Type
selector, when building Components that will have HTML.Use
Attribute
orClass
when only extending a standard HTML element, this approach allows consumers of the component to directly use all the standard element's API without extra work.
:not
pseudo-class
:not
pseudo-classAngular support using :not()
pseudo-class in selectors, for narrowing down which elements matches the selector.
Combining Selectors
You can combine multiple selectors by concatenating them.
Also you can define multiple selectors for the same Component, with a comma-separated list:
Styling Components
Encapsulation
Every Component has a view encapsulation setting that determines how the framework scopes a component's style.
The @Component
provides the encapsulation
option to control how the encapsulation is applied for the component styles, for each component.
Components can use different encapsulations. BUT this is not encouraged or recommended.
Referencing external style files
Components may use <link>
element to reference CSS files.
Additionally, inside the CSS you may use @import
rule for that.
Angular will treat these references as external styles, and they are not affected by emulated view encapsulation.
To receive data from other Components. (They are like props
in other frameworks)
Angular records inputs statically at compile-time, so they cannot be added or removed at run-time.
When extending a Component class, it's inputs are inherited by the child class.
The input
function returns a InputSignal
. So you read their values by calling the signal.
Signals created by input
are read-only.
Required input
input
It is a option to enforce that a given input
must always have a value.
Required inputs do not automatically include undefined
in type list of the input
.
input
transforms
input
transformsSpecify a transform
function to change the value of an input
when it's set by Angular.
The most common use-case for input transforms is to accept a wider range of value types in templates, often including null
and undefined
.
These transform function must be statically analyzable at build-time, meaning you cannot set transform functions conditionally or as the result of an expression evaluation.
Also they should always be pure functions. (Relying on state outside of the transform function can lead to unpredictable behavior)
You can use them for type checking or value transformation like
Angular Built-in Transformations
Angular includes two built-in transformation functions for coercing values to boolean or numbers.
booleanAttribute
: The presence of the attribute (even if empty string) indicates atrue
value, unless specific"false"
value was given.numberAttribute
: Will attempt to parse given value to a number, producingNaN
otherwise.
input
Aliases
input
AliasesTwo-way binding input
input
Since input
only creates signals that are read-only, you can overcome this limitation with two-way binding your inputs with model()
inputs.
Specifying input
inside @Component
decorator
input
inside @Component
decoratorCan be useful when a component inherits a property from a base class.
Components emit data to the outside (defining custom events), by assigning a property to the output
function.
The output
function returns an OutputEmitterRef
. You can emit an event by calling emit
method on the OutputEmitterRef
.
Angular custom events do not bubble up the DOM.
When extending a Component class, output are inherited by the child class.
Avoid chooding output
names that collide with events on DOM elements.
Avoid adding prefixes for component output
like you would with component selectors. (Like on
)
Always use cammelCase.
Emitting event data
You can pass data when calling emit
.
To have access to this data in the Parent Component, use the $event
variable.
Using aliases in output
output
output()
accepts a parameter that lets you specify a different name for the event in a template.
Specifying outputs
inside @Component
decorator
outputs
inside @Component
decoratorCan be useful when a component inherits a property from a base class.
Subscribing to outputs
Programatically
outputs
ProgramaticallyWhen creating a component dynamically, you can programmatically subscribe to output
events from the component instance. The OutputRef
includes a subscribe
method.
Angular will automatically clean up the subscription when myComp
is destroyed.
Although you can subscribe, they are not an RxJS
Observable
, so you cannot use some operators methods on it.
Converting output
to an RxJS
Observable
output
to an RxJS
Observable
You can alternatively convert it to a RxJs
Observable
with outputToObservable
.
Don't forget to clean up, by manually unsubscribing from this Observable
.
Model inputs are a special type of input that enables a component to propagate new values back to its parent component.
You may pass default
values to them and mark them as required
just like a regular input()
.
They do not support input transforms.
In the example above, value
and volume
are in sync. Their values can be updated in any of the Components and they will have the same value. (Updates are propagated up and down)
Angular automatically and implicitly creates a corresponding output()
for the model()
created.
The output
name is the same as the model
name created but suffixed with "Change".
Angular also emits this change event whenever the model is updated by its set()
or update()
methods.
The elements targeted by your component selectors do NOT act as placeholder and are NOT replaced when the page is rendered.
This means that the Host element IS rendered in the HTML.
Binding to the host element
A component can bind properties, attributes, and events to its host element.
It will add these properties to ALL the Components host elements in the application.
The newer way is to bind using host
property on @Component
.
Using @HostBinding
and @HostListener
(Old way)
@HostBinding
and @HostListener
(Old way)Prefer using the host
property over this way with decorators.
These decorators exist exclusively for backward compatibility.
Binding collisions (Preference of Values)
When you use a component in a template, you can add bindings to that component instance's element. The component may also define host bindings for the same properties or attributes.
In these cases, the following rules determine which value wins.
If both are static, the instance binding wins.
If one is static and the other dynamic, the dynamic value wins.
If both are dynamic, the component's host binding wins.
Host element access itself on it's own Component - With Service ElementRef
ElementRef
You can access the host element itself inside it's code by injecting the ElementRef
.
Check more here #using-dom-apis-elementref.
:host
css selector
:host
css selectorThis is a special CSS class for Angular, to apply CSS styles to the rendered Host element.
They are typically used inside the Component's CSS file.
Any :host
css defined will not work if the Styling Components Encapsulation is ViewEncapsulation.None
. (To get around this you may also set a class to the host element)
The Components lifecycle is a sequence of steps that happen between it's creation and it's destruction.
Each step represents a different part of Angular's process for rendering components and checking them for updates over time.
And it is tightly connected to how Angular checks your components for changes over time.
You can implement lifecycle hooks to run code during these steps.
Angular walks your application tree from top to bottom:
Checking template bindings for changes.
These lifecycles run while Angular is doing this traversal.
This traversal vists each component exactly once, so you should always avoid making further state changes in the middle of the process.
They are also executed during server-side rendering and pre-rendering.
Creation
constructor
Runs when Angular instanciates the component
Change Detection
ngOnInit
Runs once after Angular initialized all the component's inputs.
Change Detection
ngOnChanges
Runs every time the component's inputs have changed
Change Detection
ngDoCheck
Runs every time this component is checked for changes
Change Detection
ngAfterViewInit
Runs once after the component's view has been initialized
Change Detection
ngAfterContentInit
Runs once after the component's content has been initialized
Change Detection
ngAfterViewChecked
Runs every time the component's view has been checked for changes
Change Detection
ngAfterContentChecked
Runs every time this component content has been checked for changes
Rendering
afterNextRender
Runs once the next time that all components have been rendered to the DOM
Rendering
afterRender
Runs every time all components have been rendered to the DOM
Destruction
ngOnDestroy
Runs once before the component is destroyed
The
rendering
methods will only be executed in browser environments.
ngOnInit
ngOnInit
Runs only once.
Runs after Angular has initialized all the components inputs with their initial values.
This step happens before the component's own template is initialized.
This means that you can update the component's state based on its initial input values.
ngOnChanges
ngOnChanges
Runs after any component inputs have changed.
On initialization, the first
ngOnChanges
runs beforengOnInit
.
This step happens before the component's own template is checked.
This means that you can update the compoent's state based on its initial input values.
ngOnDestroy
ngOnDestroy
Runs just once right before the component is destroyed.
Angular destroys a component when it is no longer shown on the page, such as being hidden by
ngIf
or upon navigating away.
DestroyRef
DestroyRef
As an alternative you can inject an instance of
DestroyRef
.And then register a callback to be invoked upon the component's destruction by calling the
onDestroy
method.You can pass the
DestroyRef
instance to functions or classes outside your component.
Using along with ngOnInit
:
ngDoCheck
ngDoCheck
Runs before every time Angular checks a component's template for changes.
This is called during every change detection run, so it does not run only if there was a change.
You can use this lifecycle hook to manually check for state changes outside of Angular's normal change detection, manually updating the component's state.
This method runs very frequently and can significantly impact your page's performance. (Avoid using whenever possible)
During initialization, the first
ngDoCheck
runs afterngOnInit
.
ngAfterViewInit
ngAfterViewInit
Runs once after all the children in the component's template have been initialized.
You can use it to read the results of
view queries
.Attempting to change any state in this method result in an error.
ngAfterContentInit
ngAfterContentInit
Runs once after all the children nested inside the component have been initialized.
It is called after content
ng-content
has been projected into view.
You can use it to read the results of
content queries
.Attempting to change any state in this method result in an error.
ngAfterViewChecked
ngAfterViewChecked
Runs every time the children in the component's template have been checked for changes.
This method runs very frequently and can significantly impact your page's performance. (Avoid using whenever possible)
You can use it to access the updated state of
view queries
.Attempting to change any state in this method result in an error.
ngAfterContentChecked
ngAfterContentChecked
Runs every time the children nested inside the component have been checked for changes.
This method runs very frequently and can significantly impact your page's performance. (Avoid using whenever possible)
You can use it to access the updated state of
content queries
.Attempting to change any state in this method result in an error.
afterRender & afterNextRender
afterRender & afterNextRender
Lets you register a
render callback
to be invoked after Angular has finished rendering all components on the page into the DOM.afterNextRender
: Called once after the next change detection cycle.Generally will be used to perform any one-time initialization, such as for third-party libraries, or for browser-only APIs.
afterRender
: Called after every chhange detection cycle that follows.
The execution of render callbacks are not tied to any specific component instance, but instead an application-wide hook.
They must be called inside a
injection context
.They do not run during server-side rendering or during build-time pre-rendering.
A component can define queries that find child elements and read values from their injectors.
It's most commonly used to retrieve references to child components, directives, DOM elements and others.
Avoid directly writing state to child, parent or ancestor components.
Angular computes signal-based query results lazily, on demand. This means that query results are not collected unless there is a code path that reads the signal.
View Queries viewChild()
viewChildren()
viewChild()
viewChildren()
View queries retrieve results from the elements in the component's view. (The elements defined in component's own template)
Queries never pierce through component boundaries. View queries can only retrieve results from the component's template.
View queries traverse through Component's decendants.
If the query does not find a result, its value is undefined
. (This may occur if the target element is hidden)
Angular keeps the result of viewChild()
and viewChildren()
up to date as your application state changes.
Their values become available after ngAfterViewInit
lifecycle. Before this point, the value is undefined
.
Ex.:
Query a single result with viewChild()
, or multiple results with viewChildren()
, which creates a QueryList
that contains the query results.
Ex.:
Also query by referencing a Reference Template Variable.
Content Queries contentChild()
contentChildren()
contentChild()
contentChildren()
Content queries retrieve results from the elements in the component's content. (The elements nested inside the component in the template where it's used)
These queried elements doesn't have to be in the Component Template.
Queries never piece through component boundaries. Content queries can only retrieve results from the same template as the component itself.
By default, content queries find only direct children of the component and do not traverse into descendants.
If the query does ot find a result, its value is undefined
. (This may occur if the target element is hidden.)
Angular keeps the result of contentChild()
and contentChildren()
up to date as your application state changes.
Their values become available after ngAfterContentInit
lifecycle. Before this point, the value is undefined
.
Ex.:
Required Queries
By default if no results are found undefined
is return, because of this undefined
is included in the signal's return type.
In some cases where you know with certainty that a specific child is always available, and don't want the undefined
automatically included in your variable type, use required
.
Query Locators
The first parameter for view queries
and content queries
is a locator.
Most of the time you will use a component or directive as your locator. (But you can alternatively specify a string locator like #template-reference-variables-local-reference)
If more than one element defines the same template reference variable, the query retrieves the first matching one.
Angular does not support CSS selectors as locators.
Using ProviderToken
ProviderToken
For more advanced cases you can use any ProviderToken
as a locator.
This lets you locate elements based on component and directive providers.
Query Options
Options passed as second paramenter, and control how the query finds it's results.
Content descendants
By setting descendants: true
, you configure the query to traverse all descendants in the same template.
Queries however, never pierce into components to traverse elements in other templates.
View queries don't have this options because they always traverse into descendants.
Components can inject ElementRef
to get a reference to the component's host element.
Avoid direct DOM
manipulations.
Never directly manipulate the DOM
inside of other Angular lifecycle hooks.
Examples on when to use
Managing element focus.
Measuring element geometry, such as with
getBoundingClientRect
.Reading an element's text content.
Setting up native observers as
MutationObserver
,ResizeObserver
, orIntersectionObserver
.
Inheritance
When a component extends another component, or directive, it inherits all the metadata defined in the base class's decorator.
This includes:
selector
template
styles
host bindings
inputs
outputs
lifecycle methods
any other settings
Forwarding Injected Dependencies
If a base class relies on dependency injection, the child class must explicitly pass these dependencies to super
.
Overriding Lifecycle Methods
If a base class defines lifecycle methods, and a child class that also implements the same method will override the base class's implementation by default.
If you want to preserve the base class's implementation, excplicitly call the method with super
.
Programatically Rendering Components
There are two main ways do dynamically render a component.
NgComponentOutlet
NgComponentOutlet
To render components in a template.
ViewContainerRef
ViewContainerRef
To render components in the typescript code.
Use
createComponent
to dynamically create and render the component.When you create a new component like this, Angular appends it into the DOM as the next sibling of the component or directive that injected the
ViewContainerRef
.
Lazy Loading Components
To lazy load the Components in the Route: (loadComponent
)
Or you may also lazy load a Routes file, and with this you will lazy load all the components in that file: (loadChildren
)
Advanced Component Configuration
ChangeDetectionStrategy
@Component
accepts changeDetection
that controls the component's change detection mode.
ChangeDetectionStrategy.default
ChangeDetectionStrategy.default
In this mode, Angular checks whether the component's DOM needs an update whenever any activity may have occurred.
ChangeDetectionStrategy.OnPush
ChangeDetectionStrategy.OnPush
Is an optional mode that reduces the amount of checking Angular needs to perform.
In this mode, the framework only checks if a component's DOM needs an update when:
A component input has changes as a result of a binding in a template.
An event listener in this component runs.
The component is explicitly marked for check, via
ChangeDetectorRef.markForCheck
or something that wraps it, likeAsyncPipe
.
Additionally, when an
OnPush
component is checked, Angular also checks all of its ancestors components, traversing upwards the application tree.
Last updated