Angular Notes

Mani Kumar Srivastava
22 min readFeb 2, 2021

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 DOM

There 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:

  1. The template variable name.
  2. A name in the directive’s context.
  3. 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 a TemplateRef 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 matching exportAs 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/1134/working-with-dom-in-angular-unexpected-consequences-and-optimization-techniques

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 —

  1. Set the providedIn property of the @Injectable to root
  2. Include the service in the AppModule or in a module that is only imported by AppModule .
  3. 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)

  1. To access the parameters of the routes, you use the instance of ActivatedRoute .
  2. Use redirectTo and pathMatch property in the Routes configuration to redirect to a different URL. (Refer this and this )
  3. The route order in Routes configurations matter. (Refer this)
  4. There are two types of LocationStrategy for the URL in Angular : PathLocationStrategy and HashLocationStrategy. Keep in mind that these two are the sub-classes of LocationStrategy class. PathLocationStrategy supports the default ‘HTML5 pushState’ style, and HashLocationStrategy supports the ‘hash URL’ style.
    By default, the LocationStrategy is set to PathLocationStrategy . If you want to use HashLocationStrategy , then set useHash property of RouterModule.forRoot() as true . (Refer this and this)
  5. You must add a <base href=””> to the application’s index.html for pushState routing to work. (Refer this).
  6. In the Routes Configuration, the path matching (pathMatch property) strategies provided by Angular is full and prefix .
    We can also make our custom URL Matcher. Please refer this link for that.
  7. routerLinkActive directive applies the active Css to the active route.
  8. 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 the UrlTree 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.
Key differences. (Snap taken from Angular Docs)

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 the FormControl instance.
  • Latest input value element is then set, using setValue, into the FormControl instance and this instance emits the new value through its valueChanges 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 the FormControl instance is called, which updates the FormControl value.
  • This FormControl instance emits the new value through the valueChanges 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 the FormControl instance.
  • Latest input value element is then set, using setValue, into the FormControl instance and this instance emits the new value through its valueChanges observable.
  • Any subscriber listening to the valueChanges observable receive the new value.
  • The ControlValueAccessor also calls the NgModel.viewToModelUpdate() method which emits an ngModelChange 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 the NgModel 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 internal FormControl 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 the valueChanges 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 -

  1. Using setValue()
  2. 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

  1. 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

--

--