Angular Notes
1) Unidirectional Data Flow
The data change works from parent to child, not other way round
(Reference: https://angular.io/guide/glossary#unidirectional-data-flow)
2) Angular Lifecycles
During the life of a component and directive, we may need to execute some logic only when certain events happen.
E.g. Deciding what to do as soon as a component (its HTML and JS code) is placed at its appropriate place in the DOM or deciding what to do when a data-property of a component is changed causing a cascading change down the chain.
Therefore, there is a provision of lifecycles (or checkpoints) in components or directives, which allows us to execute some custom code.
You can find more details in its documentation. Read it thoroughly to get a good understanding.
But few important points are -
In layman terms, lifecycle hooks are called in this way :
• First it detect changes through ngOnChange()
• Call ngOnInit()
• Rechecks the changes through ngDoCheck()
• Call hooks which are related to external content rendering; ngAfterContentInit(), ngAfterContentChecked()
• Call hooks which are related to component’s and its child’s view rendering;
ngAfterViewInit(), ngAfterViewChecked()
• ngOnDestroy() on components removal from DOMThere is something called as @ViewChild and @ContentChild, which you should look more into
3) View Encapsulation
An important concept wherein we decide the strategy to inject the CSS to the component. Types of View Encapsulation are —
• ViewEncapsulation.ShadowDom
• ViewEncapsulaton.Emulated
• ViewEncapsulation.None
(Reference : https://angular.io/guide/view-encapsulation)
4) Template Reference Variable
Generally, a parent component can not access the property and methods of a child component. But it can be done by creating a template reference variable for the child element and then reference that variable within the parent template. The downside of this technique is that you can only avail this only in the parent html template, not in the JS component. For accessing the child in the JS Component, use @ViewChild there.
Also refer to Point#15 of this article to know more.
(References: Component Interaction)
5) Parent-Child communication through a Service
Although the title is self-explanatory, but the thought of it may not occur at the right moment. So, remember that we also have this method
(Reference: Parent-Child Service Communication)
6) Components Styles and Scoping
How does Angular scope a CSS to a particular component only? What does happen behind the hood that CSS meant for Component 1 does not interfere with the styling of Component 2, which has the similar CSS styling as to Component 1?
It keeps an index of host and its child using _nghost-c* and _ngcontent-c*, and these indexes are referred before applying the CSS styling. More details are on this blog of Angular University. Read the blog to get the more understanding
(Reference : https://angular.io/guide/component-styles)
7) Dynamic Components
This strategy is best used when we want to inject a lot of components in the same placeholder. Eg. The ad-campaign of a company on its website.
It is a very important concept. So learn it throughly
(Reference: https://angular.io/guide/dynamic-component-loader)
8) Angular Elements
How does Angular create HTML like elements to use in the DOM? What is the role of createCustomElement() method? Checkout the link in the reference.
(Reference : https://angular.io/guide/elements#how-it-works)
9) Text Interpolation
This technique allows you to resolve the template expression in the HTML template, using {{ }} symbol.
Template expressions are similar to JS expression, but for text interpolation to work properly, there are somethings that you can not put in the template expressions, such as Assignment Operators, Bitwise Operators, Increment/Decrement Operators etc. The complete list is here. Also look at template expression operators in the same link.
Interpolated expressions have a context, i.e. a particular part of the application to which the expression belongs. Typically, this context is the component instance.
Template expressions cannot refer to anything in the global namespace, except undefined
. They can't refer to window
or document
. Additionally, they can't call console.log()
or Math.max()
and they are restricted to referencing members of the expression context.
The context against which an expression evaluates is the union of the template variables, the directive’s context object — if it has one — and the component’s members. If you reference a name that belongs to more than one of these namespaces, Angular applies the following logic to determine the context:
- The template variable name.
- A name in the directive’s context.
- The component’s member names.
Angular executes template expressions after every change detection cycle
(Reference: https://angular.io/guide/interpolation)
10) Template Statement
These are the statements that we can use to respond to certain event in the HTML. E.g.
<button (click)=”takeAction()”> Click Me! </button>
takeAction()
is the example of a template statement.
The rules for template statement are almost similar to template expression, with few exceptions that
- We can use assignment operator ‘=’
- We can also do statement chaining with the semicolon ‘;’. E.g.
<button (click)=”takeActionOne();takeActionTwo();takeActionThree()”>
Click Me!
</button>
(Reference: https://angular.io/guide/template-statements)
11) Pipes
Pipes are useful in formatting a value in template expression.
To create a custom pipe, follow this simple process.
What is a Pure Pipe ?
By default, pipes are defined as pure so that Angular executes the pipe only when it detects a pure change to the input value. A pure change is either a change to a primitive input value (such as String
, Number
, Boolean
, or Symbol
), or a *changed object reference (such as Date
, Array
, Function
, or Object
).
*
Change is referred to the change in object reference, not to the change in the content of the object
How does change detection work in a pure pipe? Please read this section
Impure Pipe: To execute a custom pipe after a change within a composite object, we need to define the pipe as impure.
How to detect IMPURE changes in the composite object ? Please read this section.
— — — — — — — — —
If you have an observable for the template expression, you might wanna use AsyncPipe . If you does not, then you will have to subscribe, expand, extract, expose and unsubscribe the observable yourself. More on that here
We can still create a custom impure pipe for handling the observable. And it might have a benefit as well for some case. In case of caching an HTTP request, as shown in this example, we can use a custom IMPURE pipe.
— — — — — — — — — -
Important : Use JsonPipe to show the data in the DOM
(Reference: https://angular.io/guide/pipes)
12) Property Binding
Do remember that what comes between []
for binding will always be a property than an attribute, even though identifier for both may look the same. E.g.
<img [src]="something" />
Even though src
attribute and src
property identifier is same, the binding is happening to src
property.
There is a difference between a property and an attribute. Do understand the difference, please read this article.
Property Binding will never execute a malicious content, rather it will print that content as it is. E.g. See this section.
(Reference : https://angular.io/guide/property-binding)
13) Binding Attribute, Class and Style
Although we mentioned earlier that what comes within the binding syntax is the property, but there is a with which we can bind the attribute, class or style of an element.
Syntax for binding to an attribute
<p [attr.attribute-you-are-targeting]=”expression”></p>
— — — — — — — -
For binding to the a single CSS class, the syntax is in this format
[class.sale] = “singleCSSExpression”
singleCSSExpression
evaluates to true/false value
For binding to multiple CSS classes, the syntax goes in this way :
[class]=”multipleCSSExpression”
the multipleCSSExpression
can be one of
- A space delimited string of class names
- An object with the class name as the key and truthy/falsy expression as the value
- An array of class names
— — — — — — — — — — — — — — — -
For binding to the single CSS style, the syntax goes this way :
[style.width] = “singleStyleExpression”
singleStyleExpression
evaluates to a value which sets that style attribute.
(Note this : [style.width.px] = “100”
)
For binding to the multiple CSS style, the syntax goes this way :
[style] = “multipleCSSExpression”
the multipleCSSExpression can be one of
- string list of styles such as
"width: 100px; height: 100px;"
. - An object with style names as the keys and style values as the values, such as
{width: '100px', height: '100px'}
.
IMPORTANT : The NgStyle directive can be used as an alternative to direct [style] bindings. However, using the above style binding syntax without NgStyle is preferred because due to improvements in style binding in Angular, NgStyle no longer provides significant value, and might eventually be removed in the future.The NgStyle directive can be used as an alternative to direct [style] bindings. However, using the above style binding syntax without NgStyle is preferred because due to improvements in style binding in Angular, NgStyle no longer provides significant value, and might eventually be removed in the future.
— — — — — — — — — — -
The classes and styles binding are applied according to the precedence. Check that list here .
You can inject attribute to a component or directive, as mentioned in this section.
Remember, use @Input() when you want to keep track of the attribute value and update the associated property. Use @Attribute() when you want to inject the value of an HTML attribute to a component or directive constructor.
(Reference : https://angular.io/guide/attribute-binding)
14) Two way data binding in component
For two-way data binding to work, the @Output()
property must use the pattern, inputChange
, where input
is the name of the @Input()
property. For example, if the @Input()
property is size
, the @Output()
property must be sizeChange
.
Because no native HTML element follows the x
value and xChange
event pattern, two-way binding with form elements requires NgModel
(Reference: https://angular.io/guide/two-way-binding)
15) Template Variable (Read the doc again)
Template variables help to use data from one part of the TEMPLATE in other part of the TEMPLATE. This also means that template variable can only be used in the HTML Template, not in the component.
A template variable can refer to the following —
- a DOM element within a template
- a directive
- a element
- TemplateRef
- A Web component
Syntax —
<input #phone placeholder=”phone number” />
<!-- lots of other elements -->
<!-— phone refers to the input element; pass its `value` to an event handler --><button (click)=”callPhone(phone.value)”>Call</button>
The value assigned to a template variable is different depending upon what type of element it has been put at —
- If you declare the variable on a component, the variable refers to the component instance.
- If you declare the variable on a standard HTML tag, the variable refers to the element.
- If you declare the variable on an
<ng-template>
element, the variable refers to aTemplateRef
instance, which represents the template. (Look at Structural Directive to know more) - If the variable specifies a name on the right-hand side, such as
#var="ngModel"
, the variable refers to the directive or component on the element with a matchingexportAs
name.
Note — Template Reference Variable in the Structural Directive is an important concept. Do study it thoroughly in Directive Section in Angular Docs.
Note : You might have to read Directive to understand it better. So back to it after reading that.
(Reference : https://angular.io/guide/template-reference-variables)
16) Built-In Directives
Directives are classes that adds additional behaviour to elements in your Angular application.
Types of Angular Directives :
- Components
- Attribute Directive
- Structural Directive
— — — — — — — — — — — — — -
The most common built-in Attribute Directive in Angular is —
- NgClass
- NgStyle
- NgModel
Go to this link to know about how to use these attribute directives.
— — — — — — — — — — — — — -
The most common built-in Structural Directive in Angular is —
- NgIf
- NgFor
- NgSwitch
Go to this link to know about how to use these attribute directives.
— — — — — — — — —
To get the index of *ngFor
, add a semicolon and let i=index
. E.g.
<div *ngFor=”let item of items; let i=index”>
{{i + 1}} — {{item.name}}
</div>
— — — — — — — — — -
To track the items in *ngFor
, use trackBy
. Refer this link.
— — — — — — — — — -
To host a directive without a host-element, you can use <ng-container>
. The Angular <ng-container>
is a grouping element that doesn't interfere with styles or layout because Angular doesn't put it in the DOM.
— — — — — — — — —
Switching cases with NgSwitch
NgSwitch
is a set of three directives —
- NgSwitch
- NgSwitchCase
- NgSwitchDefault
Refer this link to know more.
(Reference : https://angular.io/guide/built-in-directives)
17) Attribute Directives
Please refer this blog post to know Attribute Directives in detail.
(Reference: https://angular.io/guide/attribute-directives)
18) Structural Directives
Structural directives are used for manipulating the structure of the DOM. Eg NgIf, NgFor.
The example for custom ngFor
structural directive can be found here . Go through the code carefully.
Also have a look at this repository too to know commit wise changes.
(Reference : https://angular.io/guide/structural-directives)
19) Difference between ng-template and ng-container
There is a detailed blog of Angular University on this topic. Here is the link.
In short, one difference is that we can use sugared Angular Directive in ng-container
but not in ng-template
.
Read that blog for ngTemplateOutlet
too.
19a) DOM Manipulation
There is an interesting articles on DOM Manipulation covering @ElementRef, @TemplateRef, @ViewContainerRef etc . Please find it here.
It is a bad idea to directly manipulate the DOM native elements. e.g. Using reference of nativeElement
fromElementRef
is not recommended by Angular. Instead use Renderer2
Service to manipulate the DOM. But there is not one renderer in Angular. Each component has some view encapsulation type associated with it — Emulated, Shadow and None. Depending on this, the renderer is assigned. But there is still a default renderer.
When it comes to adding/removing a template in the DOM, we must not use the renderer. As an example, Using a renderer to remove an element will remove it from the DOM , but not from the Angular’s View Hierarchy. That’s why ViewContainerRef
is required.
Watch this video for more details.
Some other links :
https://indepth.dev/posts/1054/here-is-what-you-need-to-know-about-dynamic-components-in-angular
20) Providing dependencies
A provider is an instruction to the Dependency Injection System on how to obtain a value for the dependency.
We can set the scope of the dependency using the providers. In other words, we can set whether a dependency needs to be available throughout the application or to only some parts, with only the providers.
#20.1) To set the dependency in root, configure the @Injectable like this ,
@Injectable({
providedIn: 'root'
})
export class SomeService
#20.2) To set the dependency in a particular @NgModule, configure the @Injectable like this,
@Injectable({
providedIn: SomeModule
})
export class SomeService
What this means is that SomeService
will be available in the application only when you import the SomeModule
.
This method is preferred over the method in #20.3 because it enables the tree-shaking of the service if nothing injects it. This implies that it wont be a part of the bundle.
#20.3) When it is uncertain to mention the module in the service, like in #20.2, then we can provide the service in the module itself.
@NgModule({
providers: [SomeService]
})
export class SomeModule
#20.4) providedIn: ‘any’
@Injectable({
providedIn: 'any'
})
export class SomeService
With providedIn: 'any'
, all eagerly loaded modules share a singleton instance; however, lazy loaded modules each get their own unique instance, as shown in the following diagram.
#20.5) To limit a provide scope with components only
@Component({
/*...*/
providers: [SomeService]
})
export class SomeComponent
Providing a service in the component limits the service only to that component and its descendants. Other components in the same module can’t access it.
— — — — — — — — —
In an eagerly loaded app, the root application injector makes all of the providers in all of the modules available throughout the app.
When Angular lazy loads a module, it creates a new injector. This injector is a child of the root application injector. When the router creates a component within the lazy-loaded context, Angular prefers service instances created from these providers over the service instances of the application root injector.
Any component created within a lazy loaded module’s context, such as by router navigation, gets the local instance of the service, not the instance in the root application injector. Components in external modules continue to receive the instance created for the application root. (Read this excerpt)
There is something called as Component.viewProviders
. Do read about it.
(Reference : https://angular.io/guide/providers)
21) DI Providers
A dependency provider configures an injector with the DI Token, which that injector uses to provide the runtime version of a dependency value.
Let’s look at the ways with which we can provide the dependencies to the providers
array.
#21.1) Class name as DI Token
providers: [SomeClass]
In this, class name itself is registered as the DI token in the dependency injection system. This syntax is the shorthand expression that expands into a provider configuration, defined by the Provider Interface
. The expanded version is
providers: [
{provide: SomeClass, useClass: SomeClass}
]
#21.2) Class Name other than the DI Token
providers: [
{provide: ADIToken, useClass: SomeClass}
]
This code tells the injector to return a SomeClass
instance when the component asks for that instance using ADIToken
.
#21.3) Aliasing the existing class provider
providers: [
NewLogger,
{provide: OldLogger, useExisting: NewLogger}
]
To alias a class provider, specify the alias and the class provider in the providers
array with the useExisting
property.
In the above example, the injector injects the singleton instance of NewLogger
when the component asks for either the new or the old logger. In this way, OldLogger
is an alias for NewLogger
.
Be sure you don’t alias OldLogger
to NewLogger
with useClass
, as this creates two different NewLogger
instances.
#21.4) Using forwardRef for circular dependency
In case you need to provide the same component in the same components providers array, you can use forwardRef
. Look it here.
#21.5) Injecting an Object
Use useValue
in the providers array for injecting an object. Have a look here.
Note : You can also create an InjectionToken
#21.6) Using useFactory
This provider configuration can be used when we want to create a changeable, dependent value based on information unavailable before run time. Have a look here.
(Reference : https://angular.io/guide/dependency-injection-providers)
22) Singleton Services
If a module defines both provides and declarations, then loading the module in multiple feature module would duplicate the registration of the services.
A singleton service implies that in whole app, there exists only once instance of that service.
Ways to create a singleton service —
- Set the
providedIn
property of the@Injectable
toroot
- Include the service in the
AppModule
or in a module that is only imported byAppModule
. - Using
forRoot
,forChild
pattern
What is forRoot, forChild pattern?
forRoot
and forChild
are just static methods methods in a module which tells whether to load that module with the providers array or without.
With forRoot
, you can import the module in the root module with the providers
. With forChild
method, you can only import the module in a child module without the providers
.
To understand more, you can refer this link.
Prevent the reimports of a module
Once a module is loaded in a root module, we can also prevent the reimports of that module in a child module. There is a small excerpt associated to that.
(Reference : https://angular.io/guide/singleton-services)
23) Routing
(Note : Only important things are mentioned here, not all. For complete info, refer Routing Doc 1 and Routing Doc 2 in Angular Docs)
- To access the parameters of the routes, you use the instance of
ActivatedRoute
. - Use
redirectTo
andpathMatch
property in theRoutes
configuration to redirect to a different URL. (Refer this and this ) - The route order in Routes configurations matter. (Refer this)
- There are two types of
LocationStrategy
for the URL in Angular :PathLocationStrategy
andHashLocationStrategy
. Keep in mind that these two are the sub-classes ofLocationStrategy
class.PathLocationStrategy
supports the default ‘HTML5 pushState’ style, and HashLocationStrategy supports the ‘hash URL’ style.
By default, theLocationStrategy
is set toPathLocationStrategy
. If you want to useHashLocationStrategy
, then setuseHash
property ofRouterModule.forRoot()
astrue
. (Refer this and this) - You must add a
<base href=””>
to the application’sindex.html
forpushState
routing to work. (Refer this). - In the Routes Configuration, the path matching (
pathMatch
property) strategies provided by Angular isfull
andprefix
.
We can also make our custom URL Matcher. Please refer this link for that. routerLinkActive
directive applies theactive
Css to the active route.- Use
children
property in the routing configuration to add the child routes.
— — — — — — — — — — —
23.1)
The router outlet component (with selector as <router-outlet></router-outlet>
) serves as a placeholder where the routed components are rendered. (Refer this. )
We can also configure our routes to be rendered in a particular <router-outlet>. This implies that there can be more than one <router-outlet>. It is mentioned below.
23.2) Wild Card Routes
Wild Card Routes are used to intercept invalid routes and handle them gracefully. It is mostly used for handling ‘404 Error’. Use ‘**’ in the path property of Routes Configuration to declare it as a Wild Card Route.
Please note that the router selects the route with the first-match-wins strategy. Since wild-card route is the least specific route, place it at the end of the Routes Configuration. (Please refer this link for more info)
23.3) Module import order matters
While importing the modules that have its own route configurations, we need to place the module in the correct order (Please note that we are talking about normal module load, not lazy-loading). If not placed rightly, e.g. if the module containing the wild-card route is placed first than other modules, then all the routes will match the wild card route, and the application will be broken. Please refer this excerpt.
23.4) Route Parameters
Use routerLink
directive in the anchor tag to navigate to a component with a route params. You can also use navigation methods provided in Router class.
Use the ActivatedRoute
instance to access the route params. paramMap
method of the ActivatedRoute
returns an observable, which when subjected to right rxjs pipe methods, can be used to access the route params. Please refer this section.
--- IMPORTANT ---
When it comes to component reuse, the standard way is to fetch the route params using Observable. If you are sure that component will not be reused, then you can avail snapshot method of ActivatedRoute.
You can pass optional parameters, which are not the standard route params, in the route as well. Please refer this.
<Write something about routable animations once you read about it>
23.5) Multiple router-outlets in the template
A template can also have any number of named outlets. Each named outlet has its own set of routes with their own components. Multiple outlets can display different content, determined by different routes, all at the same time.
<router-outlet></router-outlet> // Default
<router-outlet name="otherOutlet"></router-outlet> // Named
To add the route to be rendered in named outlet, mention the outlet in the routes configuration using outlet
property.
Specifying the outlet only in the routes configuration is not enough. You need to specify it in the routerLink
or in the navigate
method of the Router too.
It is highly recommended that you refer to this section for more details.
23.6) Route Guards
Sometimes you need to control the access to different parts of the application for various reasons. You use Route Guards to handle that.
A guard’s return value controls the router’s behaviour —
- If it returns
true
, the navigation process continues. - If it returns
false
, the navigation is cancelled and the user stays put. - If it returns a
UrlTree
, the current navigation cancels and a new navigation is initiated to theUrlTree
returned.
The guard can also tell the router to navigate elsewhere, effectively canceling the current navigation. When doing so inside a guard, the guard should return false
;
The guard might return its boolean answer synchronously. But in many cases, the guard can’t produce an answer synchronously. The guard could ask the user a question, save changes to the server, or fetch fresh data. These are all asynchronous operations.
Accordingly, a routing guard can return an Observable<boolean>
or a Promise<boolean>
and the router will wait for the observable to resolve to true
or false
.
The observable provided to the Router
must also complete. If the observable does not complete, the navigation does not continue.
The Router supports following route guards —
CanActivate
to mediate navigation to a route.CanActivateChild
to mediate navigation to a child route.CanDeactivate
to mediate navigation away from the current route.Resolve
to perform route data retrieval before route activation.CanLoad
to mediate navigation to a feature module loaded asynchronously. See this section for its implementation.
Look at the implementation of all the guards from here.
You can have multiple guards at every level of a routing hierarchy. The router checks the CanDeactivate
guards first, from the deepest child route to the top. Then it checks the CanActivate
and CanActivateChild
guards from the top down to the deepest child route. If the feature module is loaded asynchronously, the CanLoad
guard is checked before the module is loaded. If any guard returns false, pending guards that have not completed will be canceled, and the entire navigation is canceled.
Additionally, a component-less route makes it easier to guard child routes.
23.7) Lazy Loading
Once an application grows large, it is prudent to load the modules as and when it is required.
To employ lazy-loading, use loadChildren
key instead of children
in Routes Configuration and put a function that returns a promise using the browser’s built-in syntax for lazy loading code using dynamic imports. e.g.
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
},
The lazy loading and re-configuration happen just once, when the route is first requested; the module and routes are available immediately for subsequent requests.
Please refer this section for more details.
23.8) Preloading : background loading of feature areas
Preloading allows you to load modules in the background so that the data is ready to render when the user activates a particular route.
Please look at this section for more details.
Also, look at the Custom Preloading Strategy.
24) Forms
Angular provides two different approaches to handling user input through forms —
- Template Driven : These forms rely on directives in the template to create and manipulate the underlying object model. They are used for a simple use-case and easy to add to an app, but they don’t scale up as well as Reactive Forms.
- Reactive : These forms provide direct, explicit access to the underlying forms object model. Compared to template-driven forms they are more scalable, reusable and testable. They are built around observable streams.

Both template-driven and reactive forms track values changes between
- the form input elements that users interact with
AND
- the form data in your component model
Common form foundation classes
FormControl, FormGroup, FormArray and ControlValueAccessor.
24.1) Setup of Form Model
24.1.1) In Reactive Forms : With reactive forms, you define the form model directly in the component class. The [formControl]
directive links the explicitly created FormControl
instance to a specific form element in the view, using an internal value accessor.
In Reactive Forms, the form model is the source of truth.
For detailed info, look here.
24.1.2) In Template-Driven Forms : In template-driven forms, the form model is implicit, rather than explicit. The directive NgModel
creates and manages a FormControl
instance for a given form element. But do note that FormControl is used in this approach too.
In Template-Driven forms, the source of truth is the template.
For detailed info, look here.
24.2) Data Flow
Angular must keep the form in sync with the form model, and vice versa. The strategies used in Reactive and Template-Driven approach are somewhat identical, with only minor changes.
24.2.1) In Reactive Forms
From View to Model :
- User types a value into the input box.
- Input box fires an input event with the latest value.
- The
ControlValueAccessor
listening for the event in the form’s input element immediately relays the new value to theFormControl
instance. - Latest input value element is then set, using
setValue
, into theFormControl
instance and this instance emits the new value through itsvalueChanges
observable. - Any subscriber listening to the valueChanges observable receive the new value.
Do look at the corresponding flow diagram here.
From Model to View
- The
setValue
method of theFormControl
instance is called, which updates theFormControl
value. - This
FormControl
instance emits the new value through thevalueChanges
observable. - Any subscriber to the
valueChanges
observable receive the new value. - The
ControlValueAccessor
on the form input element updates the element with the new value.
Do look at the corresponding flow diagram here.
24.2.2) Template-Driven
From View to Model:
- User types a value in the input element box.
- The input element fires an input event.
- The
ControlValueAccessor
listening for the event in the form’s input element immediately relays the new value to theFormControl
instance. - Latest input value element is then set, using
setValue
, into theFormControl
instance and this instance emits the new value through itsvalueChanges
observable. - Any subscriber listening to the valueChanges observable receive the new value.
- The ControlValueAccessor also calls the
NgModel.viewToModelUpdate()
method which emits anngModelChange
event. - Because the component template uses two-way data binding for the property, that property in the component is updated to the value emitted by the
ngModelChange
event.
Do look the corresponding flow diagram here.
From Model to View
- The property value is updated in the component.
- Change detection begins.
- During change detection, the
ngOnChanges
lifecycle hook is called on theNgModel
directive instance because the value of one of its inputs has changed. - The
ngOnChanges()
method queues an async task to set the value for the internalFormControl
instance. - Change detection completes.
- On the next tick, the task to set the
FormControl
instance value is executed. - The
FormControl
instance emits the latest value through thevalueChanges
observable. - Any subscribers to the
valueChanges
observable receive the new value. - The control value accessor updates the form input element in the view with the latest property value.
Do look the corresponding flow diagram here.
24.3) Mutability of the data model
- Reactive Forms keep the data model pure by providing it as an immutable data structure.
- Template-Driven Forms rely on mutability
For more, look this.
24.4) Reactive Forms in Detail
Please note that here, only those terms and concept are listed which are essential to be remembered. For complete details, go to this link.
FormControl
is to track the value of the single input element. We can club these FormControl
to get something called as FormGroup
.
There are two ways to update the value of the form model in FormGroup
-
- Using
setValue()
- Using
patchValue()
Visit this to know more about updating the value.
— — — — — — -
Creating form control instances manually can become repetitive when dealing with multiple forms. The FormBuilder
service provides convenient methods for generating controls. Visit this to know more.
24.5) Template-Driven Forms in Detail
Template-Driven Forms rely on directives defined in the FormsModule
. They are — NgModel
, NgForm
and NgModelGroup
. For more info, refer this .
As soon as you import FormsModule
, NgForm
directive becomes active by default on all <form>
tags. You don’t need to add a special selector for that.
There is a mechanism for tracking the control states in the form. E.g. If the form element has been touched, then apply ng-touched
class etc. For more details, visit this.
(Reference: https://angular.io/guide/forms)
24.6) Validation in Forms
For validating inputs in template-driven forms, you add the same validation attribute as you would with the native HTML form validation. Look at this link for more details.
For validating inputs in reactive forms, there are two types of validator functions — Sync Validators
and Async Validator
. There are built-in validator
functions too. Please look at this link for more details.
For defining custom validators, please look at this link. Please note that for reactive forms, we use Validator Functions
, while for template-driven forms, we use Validator Directives
.
For adding cross-field validations in reactive as well as template-driven forms, please look at this link.
For adding Async Validators
, Please look at this link.
By default, Angular disables native HTML form validation by adding the novalidate
attribute on the enclosing <form>
and uses directives to match these attributes with validator functions in the framework. If you want to use native validation in combination with Angular-based validation, you can re-enable it with the ngNativeValidate
directive.
24.7) Dynamic Forms
Please look at this link for an example on Dynamic Forms.
25) HTTP Client
The module which needs to be imported in the @Ngmodule
for accessing the http utilities is HttpClientModule
.
General Information
- In Angular Version ≤8, We can access the private and protected property of a component in its respective template. It is not so in the Angular Version > 8