Tech Point Fundamentals

Saturday, December 16, 2023

Angular Interview Questions and Answers - Part 13

Angular Interview Questions and Answers - Part 13

Angular-Interview-Questions-And-Answers

Angular is a popular open-source single-page application design framework and development platform. It is a robust front-end JavaScript framework that is widely used for front-end application development. Nowadays Angular is a very common frontend technology so it is very important for the interview point as well. 

Introduction


This is the Angular Interview Questions and Answers series. Here we will see 200+ Most Frequently Asked Angular Interview Questions. This is the 13th part of the Angular Interview Questions and Answer series.

I will highly recommend to please do visit the following parts before continuing to this part:


Please do visit our YouTube Channel here to watch Interview Questions & Answers and important technology videos.

In this part we will discuss the following Important Angular Interview Questions:

Q149. What is Dependency Injection in Angular? What are the advantages of Dependency Injection?
Q150. What are the different components of the Angular Dependency Injection Framework? How does dependency injection work in Angular?
Q151. What do you mean by Hierarchical Dependency Injection in Angular? 
Q152. What is an Injector Tree? What are the different types of Injector Hierarchies in Angular? 
Q153. What is ModuleInjector Tree in Angular? How can you register services at the module level?
Q154. What is the use of @Injectable decorator in Angular? What is root-level Service Registration?
Q155. What is the root Module Injector in Angular?
Q156. What is PlatformInjector in Angular? What is the difference between platform vs. root injector?
Q157. What is the NullInjector in Angular?
Q158. What is the difference between the @Injectable() vs @ngModule() service injector?
Q159. What is the difference between Lazy Loaded vs Eagerly Loaded service provider scope?

Angular Interview Questions and Answers: Part 13


Q149. What is Dependency Injection in Angular? What are the advantages of Dependency Injection?

Dependency Injection (DI) in Angular is a software design pattern in which the objects are passed in the form of dependencies instead of hard-coding them in the respective components. It is a technique used to create loosely coupled code. This makes code more maintainable and easier to test. Dependency injection is often used in frameworks like Angular, ReactJS, and VueJS. 

A dependency doesn't have to be a service always. It could be a function, or a value as well. This DI concept is extremely handy when it comes to separating the object logic creation from its consumption.

DI is a design pattern where a class receives its dependencies from an external source rather than creating them itself.  Using DI, we move the creation and binding of the dependent objects outside of the class that depends on them. Please read more about Dependency Injection here.

In the Dependency Injection, there are three classes involved: 

  1. Client Class (dependent class)
  2. Service Class (service provider)
  3. Injector Class (that resolves and injects the dependencies)

Types of  Dependency Injections: There are three types of Dependency Injection:

  1. Constructor Injection
  2. Interface Injection
  3. Setter Injection

The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency. Likewise, the @Injectable() decorator indicates that a component, class, pipe, or NgModule has a dependency on a service.

Advantages of Dependency Injection:

  1. Dependency Injection helps to enable loose coupling, which is essential in application programming. 
  2. Extending the application becomes more flexible and manageable.
  3. Dependency Injection helps in Unit testing.
  4. Boilerplate code is reduced, as initializing of dependencies is done by the injector component.
  5. It is a way to achieve IoC and follow the SOLID Principles.

Q150. What are the different components of the Angular Dependency Injection Framework? How does dependency injection work in Angular?

There are five key components in the Angular Dependency injection Framework:

1. Consumer: A Consumer is a class (Component, Directive, or Service) that needs the Dependency. 

2. Dependency: A dependency is a service that a consumer wants to consume.

3. DI Token: The Injection Token (DI Token) uniquely identifies a Dependency. We use DI Token when we register dependency.

4. Provider: The Providers Maintain the list of Dependencies along with their Injection Token. It uses the Injection Token to identify the Dependency. 

5. Injector: The Injector holds the Providers and is responsible for resolving the dependencies and injecting the instance of the Dependency to the Consumer. The Injector uses Injection Token to search for Dependency in the Providers. It then creates an instance of the dependency and injects it into the consumer.

An injector creates dependencies and maintains a container of dependency instances that it reuses, if possible. A provider is an object that tells an injector how to obtain or create a dependency.

For any dependency that you need in your app, you must register a provider with the application's injector, so that the injector can use the provider to create new instances. For a service, the provider is typically the service class itself.

Dependency Injection Process in Angular:

The first step is to create a dependency injection container. Next, you need to register all of the dependencies that your code will need with the container. Once all of the dependencies have been registered, you can then inject them into your code.

There are several other places like @NgModule where you can add a service to the provider's array. The use of the providedIn option is the other way that you can register a service. Please remember that adding @Injectable is not registering the Service. 

@Injectable({
  providedIn: 'root'
})


Q151. What do you mean by Hierarchical Dependency Injection in Angular? 

Angular creates a hierarchical dependency injection system. It creates a hierarchical tree of Injectors. Each Injector gets its own copy of Angular Providers. Together these two form the core of the Angular dependency injection framework. 

In Angular services are singletons within the scope of an injector, which means there is at most one instance of a service in a given injector. Angular DI has a hierarchical injection system, which means that nested injectors can create their own service instances. 

Whenever Angular creates a new instance of a component that has providers specified in @Component(), it also creates a new child injector for that instance. Similarly, when a new NgModule is lazy-loaded at run time, Angular can create an injector for it with its own providers.

hierarichal-DI
Image Source: indepth.dev

Child modules and component injectors are independent of each other and create their own separate instances of the provided services. When Angular destroys a NgModule or component instance, it also destroys that injector and its service instances.

With hierarchical dependency injection, you can isolate sections of the application and give them their own private dependencies not shared with the rest of the application or have parent components share certain dependencies with its child components only but not with the rest of the component tree, and so on. Hierarchical dependency injection enables you to share dependencies between different parts of the application only when and if you need to.

Q152. What is an Injector Tree? What are the different types of Injector Hierarchies in Angular? 

Angular creates the Injector for the services to be provided at different Levels. Services are singletons within the scope of an injector, which means there is at most one instance of a service in a given injector.

Types of Injector Hierarchies:

Angular basically creates two hierarchies of injector trees: Module Injector Tree and Element Injector Tree.

ModuleInjector Hierarchy: Angular Configure a ModuleInjector in this hierarchy using an @NgModule() or @Injectable() annotation.

ElementInjector Hierarchy: It is created implicitly at each DOM element. An ElementInjector is empty by default unless you configure it in the provider's property on @Directive() or @Component().

Angular creates an Injector instance for every Component, Directive, etc. that it loads.  It also creates an injector instance for the Root Module and for every Lazy Loaded module. However, eagerly loaded modules do not get their own injector but share the injector of the Root Module.

Angular creates the ModuleInjector for the services to be provided at Module Levels. On the other hand, an Element Injector Tree is created for DOM Elements like Components and directives.

Q153. What is ModuleInjector Tree in Angular? How can you register services at the module level?

Angular creates the ModuleInjector for the services to be provided at Module Levels. Module Injector tree is created for Modules (@NgModule), Root Module & for every Lazy Loaded Modules. Angular creates the Module Injector tree when the Application starts.

At the top of the Module Injector tree, Angular creates an instance of Null Injector. The Null Injector always throws an error unless we decorate the dependency with the Optional decorator. Under NullInjector Angular creates an instance of PlatformInjector. Platform Injector usually includes built-in providers like DomSanitize etc.

module-injector-tree
ImageSource: angular.io


Registering Module Level Services in Angular: 

In Angular we can register the module-level services in two ways:

1. By using the Providers Metadata of the @NgModule():

ModuleInjector is configured by the @NgModule.providers and NgModule.imports property. ModuleInjector is a flattening of all the provider's arrays that can be reached by following the NgModule.imports recursively. But Child ModuleInjector hierarchies are created when lazy loading other @NgModules.

2. By using the @Injectable() decorator with providedIn property: Either root level or platform level

By marking a class with @Injectable, Angular can analyze the class metadata and inject dependencies automatically, simplifying the management of dependencies. Also, @Injectable supports a hierarchical injector system, allowing different levels of injectors for different parts of an application. This enables more granular control over the injection scope and can be beneficial in complex applications.

The @Injectable decorator provided by the Angular framework allows classes to be decorated and registered with Angular's dependency injection system.  When a class is marked with @Injectable, Angular creates and manages instances of that class, resolving its dependencies when needed. When a class is marked with the @Injectable decorator, it becomes eligible for constructor injection.

Using the providedIn property of the @Injectable()  is preferable over using the @NgModule() providers array. Because with @Injectable() providedIn, optimization tools can perform tree-shaking, which removes services that your application isn't using. This results in smaller bundle sizes. Tree-shaking is especially useful for a library because the application that uses the library may not have a need to inject it. 

Q154. What is the use of @Injectable decorator in Angular? What is root-level Service Registration?

Marking a class with @Injectable ensures that the compiler will generate the necessary metadata to create the class's dependencies when the class is injected. This is a decorator that marks a class as available to be provided and injected as a dependency.

It has providedIn an option that determines which injectors will provide the injectable. We can then register the service at different levels: root,  platform, any 

Root Level Service Registering (default):

Beginning with Angular 6.0, the preferred way to create a singleton service is to set providedIn to root on the service's @Injectable() decorator. This tells Angular to provide the service in the application root.

To register the service at the root level, specify 'root' as the value for the providedIn property of @Injectable. Service becomes available throughout the application by registering at the root level. Now, you can use the service in any component of the application. 

When you add a service provider to the root application injector, it's available throughout the application. Additionally, these providers are also available to all the classes in the application as long they have the lookup token. You should always provide your service in the root injector unless there is a case where you want the service to be available only if the consumer imports a particular @NgModule.

The @Injectable() decorator identifies a service class. The providedIn property configures a specific ModuleInjector, here root, in the below example which makes the service available in the root ModuleInjector.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  userName = "Tech Point Fundamentals";
  constructor() {
    console.log('User Service instance created!');
  }
  getUserName(): string {
    return this.userName;
  }
}

Now, you can use the user service in any component of the application. Just import the service in the component file and include it in the constructor of the component or service where you want to use it.

import { UserService } from '../user-service.service';

export class UserComponentComponent {
  Name: string = '';

  constructor( private userService: UserService) {
    this.Name = this.userService.getUserName();
  }
}

@Inject() is a manual mechanism for letting Angular know that a parameter must be injected. @Inject decorator is only needed for injecting primitives. The primitive types are number, string, boolean, bigint, symbol, null, undefined.

import { Inject } from '@angular/core';

constructor( @Inject(String) private userService: UserService) {
    this.Name = this.userService.userName;
  }

With providedIn: 'any', all eagerly loaded modules share a singleton instance; however, lazy loaded modules each get their own unique instance. 

Q155. What is the root Module Injector in Angular?

The name "root" is a special alias in Angular but other ModuleInjector hierarchies don't have any aliases. However, you have the option to create ModuleInjector hierarchies whenever a dynamically loaded component is created, such as with the Router, which will create child ModuleInjector hierarchies.

ModuleInjector enforces the service to be used only inside a specific module. ProvidedIn metadata available in @Injectable has to be used to specify the module in which the service can be used. The value should refer to one of the registered Angular modules. The "root" is a special option that refers to the root module of the application. 

Angular 6 introduced providers with a providedIn: ‘root’. Under Root Module Injector, Angular creates an Injector instance for every Lazy loaded Module. Angular creates them only when it loads them.  They are configured with the providers from the following locations:

  1. Providers metadata of @NgModule of the Module being Lazy loaded
  2. All the services that have providedIn metadata with the value "any" in their @Injectable() decorator

All requests forward up to the root injector, whether you configured it with the bootstrapModule() method, or registered all providers with root in their own services.

Q156. What is PlatformInjector in Angular? What is the difference between platform vs. root injector?

There are two more injectors above the root Injector in the injector hierarchy: ModuleInjector and NullInjectorUnder NullInjector Angular creates an instance of PlatformInjector. Under the Platform Injector, Angular creates the Injector for the Root Module.

Platform Injector is one level higher than ModuleInject and it is only in advanced and rare situations. Every Angular application starts by executing the PreformBrowserDynamic().bootstrap method which is responsible for bootstrapping the root module of the Angular application. PreformBrowserDynamic() method creates an injector configured by PlatformModule. We can configure platform-level services using the platformBrowser() method provided by PlatformModule.

Platform Injector usually includes built-in providers like DomSanitize etc. ‘Platform’ is most likely used for creating shared services for Angular Elements.  Platform injector usually includes built-in providers but we can provide our own when creating a platform:

const platform = platformBrowserDynamic([ {
  provide: SharedService,
  deps:[]
}]);
platform.bootstrapModule(AppModule);

The bootstrapModule() method creates a child injector of the platform injector which is configured by the AppModule. This is the root ModuleInjector. The platformBrowserDynamic() method creates an injector configured by a PlatformModule, which contains platform-specific dependencies. This allows multiple applications to share a platform configuration.

Root vs Platform Injector:

"Platform" is most likely used for creating shared services for Angular Elements. "Root" is the default for most services in Angular. All the Services registered as "root" are singleton for the whole application.

The difference between ‘root’ and ‘platform’ is only noticeable when running multiple Angular applications in the same window. Both make sure that only one singleton exists even for lazy loaded modules. But when running two applications in the same window, each application has its own root injector but both share the platform injector.

Q157. What is the NullInjector in Angular?

A NullInjector is one level higher than a platform-level ModuleInjector and is in the top level of the hierarchy.  There are two more injectors above the root Injector: an additional ModuleInjector and a NullInjector

NullInjector <= ModuleInjector <= rootModuleInjector

At the top of the ModuleInjector tree, Angular creates an instance of NullInjector. Under Null Injector Angular creates an instance of PlatformInjector.

We can not register any service in the NullInjector. It resolves when the required service is not found anywhere in the hierarchy and simply throws an error. The Null Injector always throws an error unless we decorate the dependency with the Optional decorator.

Q158. What is the difference between the @Injectable() vs @ngModule() service injector?

If you configure an app-wide provider in the @NgModule() of AppModule, it overrides one configured for root in the @Injectable() metadata. You can do this to configure a non-default provider of a service that is shared with multiple applications.

Using the providedIn property of the @Injectable()  is preferable to the @NgModule() providers array because with @Injectable() providedIn, optimization tools can perform tree-shaking, which removes services that your application isn't using and results in smaller bundle sizes.

Before Angular 6, the only way to define providers was with the providers array. Services were singletons in eagerly loaded modules but could be instantiated multiple times with lazy loaded modules. Angular 6 introduced tree-shakable providers with providedIn: ‘root’.

Now with Angular 9, we have two new ways to define the providedIn scopes: any and platform

Q159. What is the difference between Lazy Loaded vs Eagerly Loaded service provider scope?

In the basic CLI-generated application, all the modules are eagerly loaded which means that they are all loaded when the application launches. Angular uses an injector system to make things available between modules. In an eagerly loaded app, the root application injector makes all of the providers in all of the modules available throughout the application.

Lazy loading is when you load modules only when you need them. They aren't loaded right away like with eagerly loaded modules. This means that any services listed in their providers arrays aren't available because the root injector doesn't know about these modules. When the Angular router lazy-loads a module, it creates a new injector. This injector is a child of the root application injector.

In Angular, NgModules are used to organize an application into cohesive blocks of functionality. By default, NgModules are eagerly loaded, which means that as soon as the application loads, all the NgModules are loaded, whether they are immediately necessary or not. This can lead to slower application startup times and increased memory usage.

On the other hand, lazy loading is a technique in Angular that allows you to load modules only when they are needed. This can help reduce the initial load time of the application and improve its performance.

Any component created within a lazy loaded module's context, such as by router navigation, gets its own local instance of child-provided services, not the instance in the root application injector.  Though you can provide services by lazy-loading modules, not all services can be lazy-loaded. For instance, some modules only work in the root module, such as the Router. The Router works with the global location object in the browser.

Lazy vs. Eager Service Provider:

When it comes to service providers, there are two strategies that can be used in Angular: eager loading and lazy loading. In an eagerly loaded app type, the root application injector makes all of the providers in all of the modules available throughout the Angular application. 

This behavior automatically changes when we use lazy loading. In lazy loading, each module has its own injector, which means that services provided in a lazy-loaded module are scoped to that module and not available outside it.

To share service between multiple lazy-loaded modules, you can use the providedIn property of the @Injectable decorator to specify a module where the service should be provided.

With Angular 9, you can provide a new instance of a service with each lazy-loaded module. With providedIn: 'any'.  All eagerly loaded modules share a singleton instance; however, lazy loaded modules each get their own unique instance.

lazy-loaded-vs-eagerloaded-provider
Image Source: angular.io

Here you can clearly see the difference between eagerly loaded vs lazy loaded service injection.


Recommended Articles



Thanks for visiting this page. Please follow and join us on  LinkedInFacebookTelegramQuoraYouTubeTwitterInstagramWhatsApp, VKTumbler, and Pinterest for regular updates.

No comments:

Post a Comment

Please do not enter any HTML. JavaScript or spam link in the comment box.