Top 90+ Angular Interview Questions And Answers for 2024

Pravin M
115 min readJul 28, 2023
Angular Interview Questions

Source:- Angular Interview Questions

For more questions and answers visit our website at Frontend Interview Questions

Angular Interview Questions For Freshers

  1. What is Angular and what are its key features ?

Angular is a popular open-source web application framework developed by Google. It is widely used for building dynamic single-page applications (SPAs) and complex web applications. Angular follows the Model-View-Controller (MVC) architectural pattern and offers a comprehensive set of features to simplify the development process. Here are some key features of Angular:

1. TypeScript: Angular is built with TypeScript, a statically typed superset of JavaScript. TypeScript adds static typing and other features to JavaScript, making it more robust and maintainable.

2. Two-way data binding: Angular provides a powerful data binding system that allows synchronization of data between the model and the view. Changes in the model automatically reflect in the view, and vice versa, eliminating the need for manual updates.

3. Component-based architecture: Angular applications are built using components, which are self-contained, reusable building blocks. Each component encapsulates its own HTML templates, CSS styles, and business logic, promoting modularity and maintainability.

4. Dependency Injection (DI): Angular has a built-in dependency injection system that helps manage the dependencies between components and services. DI makes it easier to create, manage, and test components by providing the required dependencies automatically.

5. Routing: Angular offers a powerful routing module that enables the creation of single-page applications with multiple views. Developers can define routes, navigate between different views, and load components dynamically based on the current route.

6. Reactive forms: Angular provides robust support for building complex forms with features like validation, value tracking, and handling user input. Reactive forms use an observable-based approach to managing form state and data flow.

7. Directives: Angular has a rich set of directives that allow developers to extend HTML with custom behavior. Directives enable dynamic manipulation of the DOM, adding or removing elements, applying styles, and handling events.

8. Testing: Angular provides excellent support for testing applications. It includes a testing framework called TestBed, which allows developers to write unit tests, integration tests, and end-to-end tests for their Angular applications.

9. Performance optimization: Angular includes several performance optimization techniques, such as ahead-of-time (AOT) compilation, lazy loading of modules, and tree shaking. These features help reduce the application’s initial loading time and improve overall performance.

10. Mobile support: Angular offers tools like Angular Mobile Toolkit and Angular Material, which facilitate the development of mobile-responsive applications. It provides a consistent experience across different devices and screen sizes.

Overall, Angular provides a comprehensive framework for building robust, scalable, and maintainable web applications with a focus on productivity and performance.

2. What is a Single page application ?

A single-page application is an app that doesn’t need to reload the page during its use and works within a browser.

One of the best advantages of a correctly-configured SPA is the user experience (UX), where the user enjoys a natural environment of the app without having to wait for the page reloads and other things. You remain on the same page, which is powered by JavaScript programming language.

Before we go further, there are three abbreviations you’ll see in this article: SPA — single-page application (like we’ve mentioned above)

MPA — multi-page application (a traditional app that loads new pages when you click a link)

PWA — progressive web application (a website that is built using JavaScript or its frameworks and can act like an app, i.e., you can, for example, add it to your mobile phone homepage as an app)

Advantages

The main advantage of single-page applications is its speed. Most resources SPA needs (HTML + CSS + Scripts) are loaded at the launch of the app and don’t need to be reloaded during the usage. The only thing that changes is the data that is transmitted to and from the server. As a result, the application is very responsive to the user’s queries and doesn’t have to wait for client-server communication all the time.

3. What is a component in Angular ?

In Angular, a component is a fundamental building block of the application’s user interface. It represents a part of the UI that controls a specific view and behavior. Components are typically composed of three main parts: the component class, the component template (HTML), and the component stylesheet (CSS).
Here’s an example of an Angular component:

Suppose we want to create a simple component to display information about a user:

  1. Create the component class:

// user.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-user', // The component selector used in HTML templates
templateUrl: './user.component.html', // The path to the HTML template file
styleUrls: ['./user.component.css'] // The path to the CSS styles for this component
})
export class UserComponent {
userName: string = 'test user';
age: number = 30;
}

2. Create the component template:


<!-- user.component.html -->
<div>
<h2>User Information</h2>
<p><strong>Name:</strong> {{ userName }}</p>
<p><strong>Age:</strong> {{ age }}</p>
</div>

3. Create the component stylesheet (optional):


/* user.component.css */
div {
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
}

4. Register the component in the AppModule (or another relevant module):


// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UserComponent } from './user.component'; // Import the UserComponent

@NgModule({
imports: [BrowserModule],
declarations: [UserComponent], // Declare the UserComponent
bootstrap: [UserComponent] // Set the UserComponent as the bootstrap component
})
export class AppModule { }

Now, you can use the `app-user` selector in your application’s HTML to display the user information:


<!-- app.component.html -->
<div>
<app-user></app-user> <!-- This will render the UserComponent -->
</div>

When the application runs, it will display the following output:


User Information
Name: test user
Age: 30

This is a basic example of an Angular component, and in real-world applications, components are used extensively to build complex user interfaces by combining and nesting them as needed.

3. What are the lifecycle hooks in an Angular component ?

In Angular, components have a lifecycle that consists of various phases and events. These phases are known as lifecycle hooks, and they provide opportunities to perform actions at specific moments during the component’s creation, rendering, and destruction. The following are the lifecycle hooks available in an Angular component:

  1. ngOnChanges: This hook is called when the component receives input properties and is executed before `ngOnInit()`. It allows you to react to changes in the input properties.
  2. ngOnInit: This hook is called once, after the first `ngOnChanges()`, when the component is initialized. It is commonly used for initialization logic, such as retrieving data from a server.
  3. ngDoCheck: This hook is called during every change detection run, allowing you to implement your own custom change detection logic. It is invoked frequently, so use it judiciously to avoid performance issues.
  4. ngAfterContentInit: This hook is called after the component’s content has been projected into its view. It is useful when you need to interact with content children components.

Here’s an example of how you can use the `ngAfterContentInit` hook in an Angular component:

import { Component, AfterContentInit, ContentChild } from '@angular/core';

@Component({
selector: 'app-my-component',
template: `
<ng-content></ng-content>
`
})
export class MyComponent implements AfterContentInit {
@ContentChild('myContent') myContent: ElementRef;
ngAfterContentInit() {
// This code will run after the content has been projected into the component
console.log('Content initialized:', this.myContent.nativeElement.textContent);
}
}

In this example, the `MyComponent` component has a template that includes the `<ng-content></ng-content>` tag. This tag is a placeholder where the content will be projected when the component is used.

Inside the component class, we use the `@ContentChild` decorator to get a reference to the projected content. In this case, we’re looking for an element with the template reference variable `myContent`. You can use other selectors, such as CSS classes or component types, depending on your specific use case.

The `ngAfterContentInit` method is implemented as part of the `AfterContentInit` interface, which allows us to hook into the lifecycle of the component. Inside this method, you can perform any necessary initialization or logic based on the projected content. In this example, we log the text content of the projected element to the console.

When you use the `MyComponent` component in another template and provide content to be projected, the `ngAfterContentInit` method will be called after the content has been initialized.

<app-my-component>
<div #mycontent>This content will be projected</div>
</app-my-component>

When the above code runs, the `ngAfterContentInit` method in `MyComponent` will be triggered, and it will log the text content of the projected `<div>` element to the console. Remember to include the necessary imports for `Component`, `AfterContentInit`, and `ContentChild` from the `@angular/core` module in your Angular component.

5. ngAfterContentChecked: This hook is called after the content of the component has been checked by Angular’s change detection mechanism. It is called after every check of the content children.

6. ngAfterViewInit: This hook is called after the component’s view has been initialized. It is useful when you need to interact with child components that are part of the view.

Here’s an example of how you can use the `ngAfterViewInit` hook in an Angular component:

import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';

@Component({
selector: 'app-my-component',
template: `
<div #myDiv>Some content</div>
`
})
export class MyComponent implements AfterViewInit {
@ViewChild('myDiv') myDiv: ElementRef;
ngAfterViewInit() {
// This code will run after the component's view has been initialized
console.log('View initialized:', this.myDiv.nativeElement.textContent);
}
}

In this example, the `MyComponent` component has a template that includes a `<div>l` element with the template reference variable `myDiv`. We use the `@ViewChild`decorator to get a reference to this element in the component class.

The `ngAfterViewInit` method is implemented as part of the `AfterViewInit` interface, which allows us to hook into the lifecycle of the component’s view. Inside this method, you can access and manipulate the DOM elements of the component’s view. In this example, we log the text content of the `<div>` element to the console.

When the component’s view is initialized, Angular calls the `ngAfterViewInit` method, and you can perform any necessary operations that require access to the component’s view or its child views.

Here’s an example of using the `MyComponent` component in another template:

<app-my-component></app-my-component>

When the above code runs, the `ngAfterViewInit` method in `MyComponent` will be triggered, and it will log the text content of the `<div>` element to the console.

Remember to include the necessary imports for `Component`, `AfterViewInit`, `ViewChild`, and `ElementRef` from the `@angular/core` module in your Angular component.

7. ngAfterViewChecked: This hook is called after the view of the component has been checked by Angular’s change detection mechanism. It is called after every check of the component’s view and its child views.

8. ngOnDestroy: This hook is called just before the component is destroyed and removed from the DOM. It is used to clean up resources, such as unsubscribing from observables or canceling timers.

These lifecycle hooks allow you to perform specific actions at different stages of a component’s lifecycle. By implementing and using these hooks, you can control the behavior and manage resources effectively throughout the component’s lifespan.

4. How to implement routing in Angular web components ?

Angular web components can be implemented with routing by following these steps:

1) Create the web component using Angular’s @Component decorator. This will define the component’s template, styles, and any input or output properties.

2) Define the routes for the web component using the Routes array in the component’s module. Each route should include a path and a component.


import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MyWebComponent } from './my-web-component.component';

const routes: Routes = [
{ path: 'my-component', component: MyWebComponent }
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class MyWebComponentRoutingModule { }

3) Import the RouterModule and MyWebComponentRoutingModule modules into the component’s module and add them to the imports array.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { MyWebComponent } from './my-web-component.component';
import { MyWebComponentRoutingModule } from './my-web-component-routing.module';

@NgModule({
declarations: [MyWebComponent],
imports: [
CommonModule,
RouterModule,
MyWebComponentRoutingModule
],
exports: [MyWebComponent]
})
export class MyWebComponentModule { }

4) Use the router-outlet directive in the web component’s template to display the routed components.


<router-outlet></router-outlet>

5) Use the routerLink directive in other components or templates to navigate to the web component’s route.


<a routerLink="/my-component">My Web Component</a>

6) Build and serve the application to see the web component with routing in action.

By following these steps, developers can create web components with routing using Angular. The routerLink directive can be used to navigate to the web component’s route, and the router-outlet directive can be used to display routed components within the web component.

5. What is lazy loading in Angular ?

Lazy loading in Angular is a technique that allows you to load modules and their associated resources (components, services, etc.) on-demand, rather than loading everything upfront when the application starts. This helps to improve the initial loading time of the application and optimize the overall performance.

By default, Angular loads all modules and their associated resources when the application is launched. However, with lazy loading, you can split your application into feature modules and load them dynamically only when they are needed. This way, you can reduce the initial bundle size and load only the necessary code for the current route or feature.

To implement lazy loading in Angular, you need to follow these steps:

  1. Create Feature Modules: Divide your application into feature modules that encapsulate related components, services, and other resources. Each feature module will have its own routing configuration.
  2. Configure Routes: In the main routing configuration of your application, set up the routes for the feature modules using the `loadChildren` property instead of `component`. The `loadChildren` property specifies the path to the module file to be loaded lazily.
const routes: Routes = [
{ path: 'dashboard', component: DashboardComponent },
{ path: 'products', loadChildren: () => import('./products/products.module').then(m => m.ProductsModule) },
// other routes...
];

3. Create Feature Module: In each feature module, define its own routing configuration using the `RouterModule.forChild()` method.

const routes: Routes = [
{ path: '', component: ProductListComponent },
{ path: 'details/:id', component: ProductDetailsComponent },
// other routes specific to the feature module...
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProductsRoutingModule { }

4. Build and Serve: Build your Angular application using the Angular CLI. When you navigate to a route associated with a lazy-loaded module, Angular will fetch and load the necessary module and its resources on-demand.

Lazy loading allows you to optimize your application’s performance by splitting it into smaller modules that can be loaded when needed. It helps reduce the initial loading time and improves the user experience, especially for larger applications with multiple features.

For more details, checkout this angular’s official link to understand lazy loading — Lazy loading in Angular

6. What are the ways to share data between 2 components ?

In Angular, there are several ways to share data between two components. Here are some common methods:

  1. Parent-to-child communication (Input binding): In Angular, you can share data from a parent component to a child component by using input properties. The parent component binds a value to an input property of the child component. Example:

Parent Component:

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

@Component({
selector: 'app-parent',
template: `

`
})
export class ParentComponent {
sharedData: string = 'Hello from parent!';
}

Child Component:

import { Component, Input } from '@angular/core';

@Component({
selector: 'app-child',
template: `
{{ data }}
`
})
export class ChildComponent {
@Input() data: string;
}

2. Child-to-parent communication (EventEmitter): If you need to share data from a child component back to its parent component, you can use the EventEmitter class. The child component emits events that the parent component listens to. Example:

Child Component:

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
selector: 'app-child',
template: `
Send Data
`
})
export class ChildComponent {
@Output() dataEvent = new EventEmitter();
sendData() {
const data = 'Hello from child!';
this.dataEvent.emit(data);
}
}

Parent Component:

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

@Component({
selector: 'app-parent',
template: `

{{ receivedData }}
`
})
export class ParentComponent {
receivedData: string;
receiveData(data: string) {
this.receivedData = data;
}
}

3. Service (Shared service): You can create a shared service that acts as a data-sharing intermediary between components. The service holds the shared data, and components can read and write to it. Example:

Shared Service:

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

@Injectable()
export class DataService {
sharedData: string = 'Hello from service!';
}

Component A:

import { Component } from '@angular/core';
import { DataService } from 'path-to-data-service';

@Component({
selector: 'app-component-a',
template: `
{{ dataService.sharedData }}
`
})
export class ComponentA {
constructor(public dataService: DataService) {}
}

Component B:

import { Component } from '@angular/core';
import { DataService } from 'path-to-data-service';

@Component({
selector: 'app-component-b',
template: `
Update Data
`
})
export class ComponentB {
constructor(public dataService: DataService) {}
updateData() {
this.dataService.sharedData = 'New data!';
}
}

These are some common ways to share data between two components in Angular. The method you choose depends on the relationship between the components and the specific requirements of your application.

7. What are custom directives in Angular and how to create them ?

Custom directives are a feature in Angular that allow developers to extend the functionality of HTML by creating their own custom HTML elements or attributes. With custom directives, developers can define their own behavior, such as adding event listeners, modifying the DOM, or manipulating data.

To create a custom directive in Angular, follow these steps:

  1. Create a new directive using the @Directive decorator. The decorator specifies the selector for the directive and any inputs, outputs, and other options.
  2. Define the directive class, which contains the logic for the directive. The class should implement the OnInit and OnDestroy interfaces to handle the initialization and destruction of the directive.
  3. Add the directive to the declarations array in the module that will use it. This tells Angular that the directive should be available for use in that module.

Here is an example of a simple custom directive that changes the background color of an element:

import { Directive, ElementRef, Renderer2 } from '@angular/core';

@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef, private renderer: Renderer2) { }
ngOnInit() {
this.renderer.setStyle(this.el.nativeElement, 'background-color', 'yellow');
}
ngOnDestroy() {
this.renderer.removeStyle(this.el.nativeElement, 'background-color');
}
}

In this example, the HighlightDirective sets the background color of an element to yellow when it is initialized, and removes the background color when it is destroyed. The ElementRef and Renderer2 classes are used to access and manipulate the element in the DOM.

To use this directive in a template, simply add the appHighlight attribute to an element:

<p apphighlight>
This text will have a new yellow background.
</p>

When the template is rendered, the HighlightDirective will be applied to the element, changing its background color to yellow.

8. What is the difference between ng serve and npm start ?

ng serve and npm start are both commands used in web development, but they serve different purposes depending on the context. Let’s look at the differences between `ng serve` and `npm start` with some examples:

1. `ng serve` Example:

Let’s say you’re working on an Angular project and want to run it locally for development purposes. You would navigate to your project directory in the command line and run the following command:

ng serve

This command would compile your Angular application, bundle the assets, start a development server, and watch for changes. It will then provide you with a local URL (usually http://localhost:4200) where you can access and test your application in the browser. The development server will also automatically reload the application whenever you make changes to the code.

2. `npm start` Example:

Suppose you’re working on a Node.js project that has a `start` script defined in the package.json file. The `start` script is set to execute the main application file, `index.js`. To start your application, you would navigate to the project directory and run the following command:

npm start

This command will execute the command specified in the `start` script of the package.json file, which in this case is running `index.js`. It could be any command you specify. For example, you might use `npm start` to launch a web server, initiate a build process, or perform any other necessary actions to start your application in a production or deployment environment.

Conclusion :

ng serve is used specifically for running an Angular project locally during development, providing a development server and automatic reloading. On the other hand, `npm start` is a more generic command used in Node.js projects to execute a command specified in the `start` script, often used for starting an application in a production environment.

9. What is the difference between ng add and npm install ?

The main difference between ng add and npm install lies in their purpose and functionality within the Angular ecosystem.

  1. ng add: This is a command specific to the Angular CLI (Command Line Interface). It is used to add new packages, libraries, or schematics to an Angular project. When you run `ng add`, it performs several tasks automatically, such as installing the necessary packages, configuring the project, and making any required changes to the project’s files. The `ng add` command is often used to quickly integrate third-party libraries or extensions into an Angular project with minimal effort. Suppose you want to add the Angular Material library to your Angular project. Instead of manually configuring and installing Angular Material, you can use the `ng add` command to simplify the process.

Here’s how you would do it:

ng add @angular/material

When you run this command, the Angular CLI will perform the following tasks:

  • Install the `@angular/material` package and its dependencies using `npm install`.
  • Configure the project to use Angular Material by updating the `angular.json` file.
  • Import and configure the necessary modules and styles in the project’s files (e.g., `app.module.ts` and `styles.scss`).

ng add is a convenient way to add Angular-specific packages or schematics to your project while automating the necessary setup steps.

2. npm install: This is a general command provided by npm (Node Package Manager) for installing packages from the npm registry. It is not specific to Angular but is used across various JavaScript and Node.js projects. When you run `npm install `, it installs the specified package and its dependencies into the project. It typically updates the `package.json` file to include the installed package as a dependency. However, `npm install` does not perform any specific configuration or modification of the project’s files.

Let’s say you want to install the `lodash` library, which is a popular utility library for JavaScript. In this case, you would use the `npm install` command directly, as follows:

npm install lodash

Running this command will:

  • Fetch the `lodash` package and its dependencies from the npm registry.
  • Install the package locally within your project’s `node_modules` directory.
  • Update the `package.json` file to include `lodash` as a dependency. npm install is a general-purpose command used to install any package from the npm registry into your project, regardless of the specific framework or library being used.

Conclusion

In summary, ng add is a specialized command within the Angular CLI that automates the installation and configuration of packages specifically designed for Angular projects. On the other hand, npm install is a general command provided by npm to install packages from the npm registry into any JavaScript or Node.js project, including Angular projects.

10. Can we use jQuery in Angular 2/4/5 ?

Yes ,we can using the following steps:-

STEP 1 — Install


// In the console
// First install jQuery
npm install --save jquery
// and jQuery Definition
npm install -D @types/jquery

STEP 2 — Import


// Now, within any of the app files (ES2015 style)
import * as $ from 'jquery';
//
$('#elemId').width();

// OR

// CommonJS style - working with "require"
import $ = require('jquery')
//

#UPDATE for ES6

In ES6 ‘* as $’ is not required.


import $ from 'jquery';
//
$('#elemId').width();

11. How to call an API in Angular ?

In Angular, you can call an API using the `HttpClient` module, which provides a convenient way to make HTTP requests. Here’s a step-by-step guide on how to call an API in Angular:

  1. Import the `HttpClient` module and inject it into your component or service. Make sure to import it from `@angular/common/http`.

import { HttpClient } from '@angular/common/http';

constructor(private http: HttpClient) {}

2. Use the `http.get()`, `http.post()`, `http.put()`, or `http.delete()` methods to make the desired HTTP request. These methods return an `Observable` that you can subscribe to in order to handle the response.

Here’s an example of making a GET request to retrieve data from an API:


this.http.get('https://api.example.com/data').subscribe(response => {
// Handle the response data
});

3. If the API requires headers, parameters, or a request body, you can pass them as options to the HTTP request. For example, to include headers or query parameters, you can use the `HttpHeaders` and `HttpParams` classes from `@angular/common/http`.


import { HttpHeaders, HttpParams } from '@angular/common/http';

// GET request with headers and query parameters
const headers = new HttpHeaders().set('Authorization', 'Bearer token');
const params = new HttpParams().set('param1', 'value1').set('param2', 'value2');

this.http.get('https://api.example.com/data', { headers, params }).subscribe(response => {
// Handle the response data
});

4. For POST, PUT, or DELETE requests, you can also pass the request body as the second argument to the respective method.


const book = { title: 'Example Book', author: 'John Doe' };

this.http.post('https://api.example.com/books', book).subscribe(response => {
// Handle the response data
});

Note that the examples above are using the simplified version of making HTTP requests. In a real-world scenario, you would handle error handling, unsubscribe from the `Observable` to avoid memory leaks, and potentially use other options and features provided by the `HttpClient` module.

Remember to import the `HttpClientModule` in your application’s root or feature module to enable the `HttpClient` service. This is typically done in the module’s `imports` array:


import { HttpClientModule } from '@angular/common/http';

@NgModule({
imports: [HttpClientModule],
// Other module configurations
})
export class AppModule {}

By following these steps, you can easily call an API in Angular and handle the responses in your application.

12. What is the difference between ‘dependencies’ and ‘dev-dependencies’ properties in package.json ?

The `dependencies` and `devDependencies` properties in the `package.json` file are used to manage different types of dependencies in a Node.js project. Here’s the difference between them:

  1. `dependencies`:

— The `dependencies` property is used to list the packages that are required for the project to run in a production or deployment environment.

— These packages are necessary for the application’s core functionality and are typically required at runtime.

— When you install the project dependencies using `npm install`, the packages listed in the `dependencies` section are installed.

Example:

"dependencies": {
"express": "^4.17.1",
"lodash": "^4.17.21"
}

2. `devDependencies`:

— The `devDependencies` property is used to list the packages that are only required during development, such as testing frameworks, build tools, and development-specific utilities.

— These packages are not necessary for the application to run in a production environment but are helpful during development and testing phases.

— When you install the project dependencies along with dev dependencies using `npm install`, the packages listed in both the `dependencies` and `devDependencies` sections are installed.

Example:

"devDependencies": {
"mocha": "^9.0.3",
"nodemon": "^2.0.13"
}

By separating dependencies into `dependencies` and `devDependencies`, you can distinguish between packages required for production and those required for development. This separation helps reduce the size of the production deployment by excluding unnecessary development-related packages.

Conclusion :

To summarize, `dependencies` includes packages needed for the application to run in a production environment, while `devDependencies` includes packages required during development and testing but are not necessary for the production deployment.

Angular Interview Questions For Experienced

1. What is replay subject in angular ?

In Angular, a ReplaySubject is a type of subject provided by the RxJS library. It is a variant of the Subject class and allows you to multicast values to multiple subscribers.

A ReplaySubject remembers and replays a specific number of values to any subscriber that subscribes to it. When a new subscriber subscribes to a ReplaySubject, it will immediately receive the buffered values, up to a specified buffer size or timeframe. The key features of a ReplaySubject are:

  1. Buffering: A ReplaySubject keeps a buffer of values that it has emitted. You can specify the maximum number of values to buffer using the buffer size parameter when creating the ReplaySubject.
  2. Subscription: When a new subscriber subscribes to a ReplaySubject, it immediately receives the buffered values. If the buffer size is reached, older values are dropped from the buffer to accommodate new values.
  3. Timeframe: In addition to the buffer size, you can also specify a timeframe for the ReplaySubject. With a timeframe, the ReplaySubject will only buffer values emitted within a specific time window. ReplaySubjects are useful in scenarios where you want subscribers to receive previously emitted values, even if they subscribe at a later time. For example, if you have a component that needs to fetch some initial data on initialization, you can use a ReplaySubject to cache the data and ensure that any subsequent subscribers receive the cached values.

Here’s an example usage of a ReplaySubject in Angular:

import { ReplaySubject } from 'rxjs';

// Create a ReplaySubject with a buffer size of 3
const subject = new ReplaySubject(3);
// Emit values to the ReplaySubject
subject.next('Value 1');
subject.next('Value 2');
subject.next('Value 3');
// Subscribe to the ReplaySubject
subject.subscribe(value => console.log('Received:', value));
// Output: Received: Value 1, Received: Value 2, Received: Value 3
// Emit another value
subject.next('Value 4');
// Output: Received: Value 4 (new subscriber receives the latest value)
// Subscribe again after some time
setTimeout(() => {
subject.subscribe(value => console.log('Received later:', value));
}, 2000);
// Output: Received later: Value 2, Received later: Value 3, Received later: Value 4

In the example above, the ReplaySubject buffers the last 3 emitted values. When a new subscriber subscribes, it immediately receives the buffered values. The second subscriber, which subscribes after some time, receives the buffered values that were emitted within the specified timeframe.

ReplaySubjects are a powerful tool in Angular when you need to share and replay values among multiple subscribers, especially when dealing with asynchronous data streams.

2. What is the difference between adding styles and scripts in angular.json and adding styles and scripts in index.html ?

In Angular, there is a distinction between adding styles and scripts in the `angular.json` configuration file and adding them directly in the `index.html` file. Here’s a breakdown of the key differences:

  1. `angular.json`:

The `angular.json` file is the configuration file for an Angular project. It contains various settings and options related to the project’s build process, including the configuration for styles and scripts.

In the `angular.json` file, you can specify the styles and scripts that should be included as part of the project build process. The styles are typically specified using the `”styles”` property, which accepts an array of file paths for CSS or Sass files. The scripts are typically specified using the `”scripts”` property, which accepts an array of file paths for JavaScript or TypeScript files.

These styles and scripts defined in the `angular.json` file will be automatically included and bundled as part of the build process. They will be loaded and applied to the application during runtime.

2. `index.html`:

The `index.html` file is the main HTML file for an Angular application. It is the entry point for the application and contains the basic structure of the HTML document.

In the `index.html` file, you can add external stylesheets or scripts directly using `<link>` and `<script>` tags. These tags reference external CSS or JavaScript files hosted on a server or included from a CDN. By including them in the `index.html` file, they will be loaded by the browser when the application is accessed.

The styles and scripts added directly in the `index.html` file are separate from the ones specified in the `angular.json` file. They are not part of the build process or bundling performed by Angular. Instead, they are loaded and applied by the browser directly when the `index.html` file is loaded.

In summary, the key differences are:

— Styles and scripts specified in the `angular.json` file are part of the Angular build process and bundled with the application during build time. — Styles and scripts added directly in the `index.html` file are loaded by the browser at runtime, separate from the Angular build process.

Typically, it is recommended to use the `angular.json` file for including styles and scripts that are part of the project and managed by Angular. On the other hand, adding external stylesheets or scripts in the `index.html` file is useful for including third-party libraries or custom styles and scripts that are not managed by Angular.

3. What is the difference between cold observables and hot observables ?

In RxJS, a popular library for reactive programming, observables can be categorized into two types: cold observables and hot observables. The key difference between these two types lies in how they handle the emission and subscription of values.

  1. Cold Observables:

A cold observable starts emitting values when a subscription is made. Each subscription to a cold observable triggers a separate execution of the observable’s logic. In other words, the data stream is independent for each subscriber, and each subscriber receives the full sequence of emitted values from the beginning.

For example:


import { Observable } from 'rxjs';

const coldObservable = new Observable(observer => {
console.log('Observable logic');
observer.next(1);
observer.next(2);
observer.next(3);
});

coldObservable.subscribe(value => console.log('Subscriber 1:', value));
coldObservable.subscribe(value => console.log('Subscriber 2:', value));

Output:


Observable logic
Subscriber 1: 1
Subscriber 1: 2
Subscriber 1: 3
Observable logic
Subscriber 2: 1
Subscriber 2: 2
Subscriber 2: 3

In the example above, each subscriber triggers the execution of the observable logic separately, and both subscribers receive the complete sequence of emitted values.

2. Hot Observables:

A hot observable, on the other hand, emits values regardless of subscriptions. It starts emitting values immediately upon creation, and subscribers receive only values emitted after they subscribe. The data stream is shared among subscribers, and late subscribers may miss previously emitted values.

For example:


import { Subject } from 'rxjs';

const hotObservable = new Subject<number>();

hotObservable.next(1);
hotObservable.next(2);
hotObservable.next(3);

hotObservable.subscribe(value => console.log('Subscriber 1:', value));

hotObservable.next(4);
hotObservable.next(5);

hotObservable.subscribe(value => console.log('Subscriber 2:', value));

hotObservable.next(6);
hotObservable.next(7);
</number>

Output:


Subscriber 1: 4
Subscriber 1: 5
Subscriber 1: 6
Subscriber 1: 7
Subscriber 2: 6
Subscriber 2: 7

In the example above, the hot observable starts emitting values immediately. Subscriber 1 subscribes after the first three values have been emitted and receives subsequent values. Subscriber 2 subscribes later and only receives values emitted after its subscription.

Hot observables are commonly used for events or continuous data streams, where the values are being produced independently of subscriptions.

In summary, the main difference between cold observables and hot observables is that cold observables start emitting values upon subscription and each subscription triggers a separate execution, while hot observables emit values regardless of subscriptions and late subscribers may miss previously emitted values.

4. What are the properties inside @ngModule decorator ?

What are the properties inside @ngModule decorator
What are the properties inside @ngModule decorator

5. How to generate a component using cli command without creating its spec file ?

Updated for Angular >=8 CLI For one component, use the following command:


ng generate component --skipTests=true component-name

For a single project, change or add the following in your angular.json:


{
"projects": {
"{PROJECT_NAME}": {
"schematics": {
"@schematics/angular:component": {
"skipTests": true
}
}
}
}
}

For a global setting for all your projects, change or add the following in your angular.json:


{
"schematics": {
"@schematics/angular:component": {
"skipTests": true
}
}
}

Or by using the command line


ng config schematics.@schematics/angular:component.skipTests true

For Angular < 8 Inside your angular-cli.json set the spec.component parameter to false:


{
...
"defaults" : {
...
"spec": {
...
"component": false
}
}
}

or use the — spec=false option during creation


ng generate component --spec=false component-name

6. What is RxJS ?

RxJS (Reactive Extensions for JavaScript) is a library for reactive programming using Observables, which makes it easier to compose asynchronous or event-based programs by using functional programming concepts. RxJS provides a way to represent asynchronous data streams as Observables, which can be transformed, combined, and consumed in a declarative way using operators. RxJS is based on the ReactiveX API, which was originally developed for .NET, but has since been implemented in several programming languages, including Java, Swift, and JavaScript.

In essence, RxJS provides a powerful set of tools for managing asynchronous data streams in JavaScript, enabling developers to create more efficient and flexible applications. It is commonly used in web applications to manage events and network requests, but can also be used in other contexts where reactive programming is beneficial.

Here is an example of using RxJS in JavaScript to create an Observable that emits a sequence of numbers and filters out even numbers:

const { Observable } = require('rxjs');

const source$ = new Observable(subscriber => {
let count = 0;
const intervalId = setInterval(() => {
subscriber.next(count);
count++;
}, 1000);

return () => clearInterval(intervalId);
});
const filtered$ = source$.pipe(
filter(num => num % 2 !== 0)
);
const subscription = filtered$.subscribe(
num => console.log(num),
err => console.error(err),
() => console.log('Complete')
);
setTimeout(() => {
subscription.unsubscribe();
}, 5000);

In this example, we create an Observable called source$ that emits a sequence of numbers using the setInterval function. We then create a new Observable called filtered$ by applying the filter operator to the source$ Observable, which removes even numbers from the sequence. Finally, we subscribe to the filtered$ Observable and log the emitted values to the console, and after 5 seconds we unsubscribe from the subscription to stop the Observable from emitting any more values.

7. What is the use of HttpClientModule ?

The HttpClientModule was introduced in Angular version 4.3.0.

Before Angular 4.3.0, the `HttpModule` was used to handle HTTP requests and responses. However, starting from Angular 4.3.0, the `HttpModule` was deprecated in favor of the new `HttpClientModule`.

The `HttpClientModule` provides a more modern and improved API for making HTTP requests and handling responses. It includes features like support for interceptors, response typing, and improved error handling.

To use the `HttpClientModule`, you need to import it in your Angular module:


import { HttpClientModule } from '@angular/common/http';

@NgModule({
imports: [
HttpClientModule
],
// ...
})
export class AppModule { }

Once imported, you can inject the `HttpClient` service into your components or services to make HTTP requests.


import { HttpClient } from '@angular/common/http';

@Injectable()
export class MyService {
constructor(private http: HttpClient) {
}

getData() {
return this.http.get('https://api.example.com/data');
}
}

Overall, the `HttpClientModule` provides a more robust and feature-rich way to work with HTTP in Angular applications, and it has been the recommended approach since Angular 4.3.0.

8. Is it necessary to define a constructor in a component ?

It is not necessary to define a constructor in a component in Angular. Angular provides a default constructor for components, and if you don’t define a constructor in your component class, the default constructor will be used.

The default constructor provided by Angular does not require any parameters and is often empty. It is implicitly called when a component is instantiated.

Here is an example of a component without a constructor:

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

@Component({
selector: 'app-my-component',
template: 'Hello, Angular!'
})
export class MyComponent {
// No explicit constructor defined
}

In this example, the `MyComponent` class does not have a constructor defined. Angular will automatically use the default constructor when creating an instance of `MyComponent`.

However, if you need to perform any initialization or dependency injection in your component, you can define a constructor and provide the necessary parameters. The constructor is a way to inject dependencies and initialize component properties.

import { Component } from '@angular/core';
import { MyService } from './my.service';

@Component({
selector: 'app-my-component',
template: 'Hello, Angular!'
})
export class MyComponent {
constructor(private myService: MyService) {
// Perform initialization or other logic here
}
}

In this example, the `MyComponent` class has a constructor that injects the `MyService` dependency. You can use the constructor to initialize properties or perform other necessary tasks when the component is created.

So, while it is not necessary to define a constructor in a component, you can use it to inject dependencies and perform initialization if required.

9. What are the security features in angular ?

Angular provides several security features and best practices to help developers build secure web applications. Here are some of the key security features in Angular, along with examples:

  1. Template Sanitization:

Angular automatically sanitizes user-provided inputs in templates to prevent Cross-Site Scripting (XSS) attacks. For example, consider the following template:

{{ user.name }}

If the `user.name` property contains potentially harmful HTML code, Angular automatically sanitizes it and renders it as plain text, preventing any script execution.

->We have to add code to sanitize untrusted values, The security contexts are HTML (binding inner HTML), style (CSS), attributes (binding values), and resources (referring files). We should covert the untrusted values provided by users into trusted values with DomSanitizer

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { DomSanitizer } from '@angular/platform-browser';

@Injectable()
export class SecurityService {
constructor(private sanitizer: DomSanitizer) {
}
getSafeHtml(html: string) {
return this.sanitizer.bypassSecurityTrustHtml(html);
}
}

The following methods are used for marking a value as trusted depending on the value type:

bypassSecurityTrustScript
bypassSecurityTrustStyle
bypassSecurityTrustUrl
bypassSecurityTrustResourceUrl

2. Cross-Site Scripting (XSS) Protection: Angular automatically escapes interpolated values and data bindings by default to prevent XSS attacks. For example, consider the following template:

{{ user.bio }}

If the `user.bio` property contains a script tag or any other HTML code, Angular escapes the characters and renders it as plain text, preventing script execution.

3. Content Security Policy (CSP) Support:

Angular allows you to enforce a strict Content Security Policy for your application. This helps protect against XSS attacks by defining the sources from which the application can load resources. For example, you can configure a CSP in the HTML header as follows:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://trusted-cdn.com;">

This example restricts the loading of scripts to the same origin and a trusted CDN.

4. HTTP Interceptors:

Angular’s HttpClient module provides interceptors that allow you to modify HTTP requests and responses. You can use interceptors to implement security-related features, such as adding authentication headers or handling CSRF tokens. For example, you can create an interceptor to add an authentication token to every outgoing request:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest, next: HttpHandler): Observable> {
const token = 'your-auth-token';
const authReq = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`)
});
return next.handle(authReq);
}
}

This interceptor adds an `Authorization` header with a bearer token to each outgoing HTTP request.

5. Authentication and Authorization:

Angular provides a flexible framework for implementing authentication and authorization mechanisms. You can leverage features like route guards, authentication services, and token-based authentication (e.g., JWT) to secure routes and control access to protected resources. Here’s an example of a route guard that restricts access to a specific route:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable | Promise | boolean | UrlTree {
// Check if user is authenticated, e.g., by verifying the presence of a valid token
const isAuthenticated = ...;
if (isAuthenticated) {
return true;
} else {
// Redirect to login page or show access denied message
this.router.navigate(['/login']);
return false;
}
}
}

This guard checks if the user is authenticated and allows or denies access to the protected route accordingly.

6. Avoid risky Angular APIs

Avoid Angular APIs marked in the documentation as “Security Risk.” The most common risky API we use is ElementRef. It permits direct access to the DOM and can make your application more vulnerable to XSS attacks. Review any use of ElementRef in your code carefully. Use this API as a last resort when direct access to the DOM is needed. Use templating and data binding provided by Angular, instead. Alternatively, you can take a look at Renderer2, which provides an API that can safely be used even when direct access to native elements is not supported.

These are just a few examples of the security features provided by Angular. It’s important to implement additional security measures based on your application’s requirements, such as input validation, secure communication protocols (HTTPS), proper error handling, and regular security updates for dependencies and libraries used in the application.

10. What is testbed in Jasmine ?

In the context of Jasmine, the TestBed is a utility provided by Angular for testing Angular components, directives, services, and other Angular constructs. The TestBed creates a testing module environment where you can configure and instantiate components and services to be tested.

The TestBed is part of the Angular Testing utilities and is commonly used in combination with other testing frameworks such as Karma or Jest. It provides an Angular-specific environment for testing that facilitates component creation, dependency injection, and change detection.

Here’s a basic example of using the TestBed in Jasmine:

import { TestBed } from '@angular/core/testing';
import { MyComponent } from './my.component';

describe('MyComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [MyComponent],
}).compileComponents();
});
it('should create the component', () => {
const fixture = TestBed.createComponent(MyComponent);
const component = fixture.componentInstance;
expect(component).toBeTruthy();
});
// Other test cases...
});

In this example, the `beforeEach` function is called before each test case, and within it, `TestBed.configureTestingModule` is used to configure the testing module. The `declarations` property is used to declare the components to be tested, in this case, the `MyComponent`.

The `compileComponents` function is an asynchronous operation that compiles the component’s template and dependencies.

Inside the individual test cases, `TestBed.createComponent` is used to create an instance of the component being tested. This returns a `ComponentFixture` object from which you can access the component instance (`componentInstance`) and the associated DOM element (`nativeElement`).

Using the TestBed and ComponentFixture, you can interact with and test the component’s properties, methods, and the rendered DOM.

The TestBed provides other useful methods for configuring the testing module, such as providing mock services, configuring routes, and handling dependency injection.

Overall, the TestBed in Jasmine provides a powerful testing environment for Angular applications, allowing you to create and test Angular components and services in an isolated and controlled manner.

11. What is the difference between Subject and Behaviour Subject ?

In RxJS, a popular library for reactive programming in JavaScript, there are two types of subjects: Subject and BehaviorSubject. Both are implementations of the `Subject` class but have some key differences in behavior.

  1. Subject: A `Subject` is a multicast observable that can be subscribed to by multiple observers. It acts as both an observable and an observer, meaning you can subscribe to it to receive values and also push values to it using its `next()` method. When a `Subject` emits a new value, all of its subscribed observers will receive that value.
  2. BehaviorSubject: A `BehaviorSubject` is a type of `Subject` that has a notion of “current value”. It maintains and emits the latest value to any new subscribers. When a `BehaviorSubject` is created, it requires an initial value. Any subscriber that subscribes to a `BehaviorSubject` will immediately receive the current value or the latest emitted value.

Here are the key differences between `Subject` and `BehaviorSubject`:

— Initial Value: `Subject` doesn’t have an initial value, while `BehaviorSubject` requires an initial value during its creation.

— Late Subscription: If you subscribe to a `Subject`, you won’t receive any previously emitted values. However, if you subscribe to a `BehaviorSubject` after it has emitted values, you will receive the latest emitted value immediately upon subscription.

— Default Value: If no value has been emitted by a `BehaviorSubject` before subscription, it will emit the initial value provided during creation. This is useful for cases where you want subscribers to have a default value even if they subscribe after some values have been emitted.

Here’s an example to illustrate the difference:

import { Subject, BehaviorSubject } from 'rxjs';

const subject = new Subject();
const behaviorSubject = new BehaviorSubject('Initial Value');
// Subscribe to Subject
subject.subscribe(value => console.log('Subject:', value));
// Subscribe to BehaviorSubject
behaviorSubject.subscribe(value => console.log('BehaviorSubject:', value));
// Emit values
subject.next('Value 1');
behaviorSubject.next('Value 2');
// Subscribe after value emission
subject.subscribe(value => console.log('Late Subscription to Subject:', value));
behaviorSubject.subscribe(value => console.log('Late Subscription to BehaviorSubject:', value));

Output:

BehaviorSubject: Initial Value
Subject: Value 1
BehaviorSubject: Value 2
Late Subscription to BehaviorSubject: Value 2

In the example, when we emit `’Value 1'` using the `subject`, only the subscriber that subscribed before the emission receives the value. However, when we emit `’Value 2'` using the `behaviorSubject`, both the existing subscriber and the late subscriber receive the latest value immediately upon subscription.

Conclusion:

In summary, the main difference between `Subject` and `BehaviorSubject` is that `BehaviorSubject` has an initial value and maintains and emits the latest value to new subscribers. This makes it useful in scenarios where you need to ensure that subscribers receive a default or the latest value even if they subscribe after some values have been emitted.

12. What are the advantage of using observable instead of promise for http request ?

Promise emits a single value while Observable emits multiple values. So, while handling a HTTP request, Promise can manage a single response for the same request, but what if there are multiple responses to the same request, then we have to use Observable. Yes, Observable can handle multiple responses for the same request. Let’s implement this with an example.

Promise e.g

const promise = new Promise((data) => { 
data(1);
data(2);
data(3);
}).then(element => console.log(‘Promise ‘ + element));

Output:- Promise 1

Observable e.g

const observable = new Observable((data) => {
data.next(1);
data.next(2);
data.next(3);
}).subscribe(element => console.log('Observable ' + element));

// Output
Observable 1
Observable 2
Observable 3

13. Difference between authorization and authentication. Explain the basic difference and also in the context of an angular application ?

Authentication and authorization are two distinct concepts related to user access and security in a software application, including Angular applications.

Authentication:

Authentication is the process of verifying the identity of a user or entity. It ensures that the user is who they claim to be. Authentication typically involves presenting credentials, such as a username and password, to prove identity. Once authenticated, the user is granted access to the application.

In the context of an Angular application, authentication is the process of verifying the identity of a user before allowing access to protected parts of the application. This can be achieved by implementing a login system where users provide their credentials and the application validates them against stored user data or an authentication service. Upon successful authentication, the user receives an authentication token or session, which is used to identify the user and grant access to restricted areas of the application.

Authorization:

Authorization is the process of granting or denying access to specific resources or functionalities within an application. It determines what a user is allowed to do or access based on their authenticated identity and assigned permissions. Authorization controls what actions or operations a user can perform within the application.

In an Angular application, authorization comes into play after authentication. Once a user is authenticated, the application needs to enforce access control rules to determine whether the user has the necessary permissions to perform certain actions or access specific parts of the application. This can involve roles, permissions, or other access control mechanisms. For example, an administrator may have access to certain administrative features or data, while a regular user may have limited access.

To implement authorization in an Angular application, developers typically define roles and permissions, and then apply checks and guards throughout the application to ensure that only authorized users can perform certain actions or access certain routes or components. This can involve implementing role-based access control (RBAC) or using other authorization frameworks or libraries.

In summary, the basic difference between authentication and authorization is that authentication verifies the identity of a user, while authorization controls what actions or resources that authenticated user is allowed to access within the application. Authentication is about verifying who you are, while authorization is about determining what you can do once your identity is established.

14. What is AOT in Angular ?

For better Understanding it is first important to understand what is JIT which used to be default Angular compilation mode till Angular 8. After JIT , we will se how AOT works and how its different from JIT :

Just-in-Time (JIT)

In JIT compilation mode the TS code written by the developer is compiled to JS code during the build creation. Now, this compiled js code still contains some angular specific code ( for components, decorators, change detection, Dependency Injection etc.)which is compiled at the browser end again at runtime ,with the help of JIT compiler sent along with the build .

In JIT mode when Angular application is bootstrapped in the browser, the JIT compiler performs a lot of work to analyze the components in the application at runtime and generate code in memory. When the page is refreshed, all the work that has been done is thrown away, and the JIT compiler does the work all over again.

Ahead-of-Time (AOT)

The TS code written by the developer is compiled to JS code, this js has already been compiled for angular as well. Now, this compiled js code is compiled by the browser again so that the html can be rendered. But, the catch here is that the features of angular have already been taken care of by AOT compiler and hence the browser don’t have to worry much about component creation, change detection, Dependency Injection. So, we have :

Faster rendering

There’s no need to download the Angular compiler if the app is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload.

Detect template errors earlier

The AOT compiler detects and reports template binding errors during the build step before users can see them.

Better security

AOT compiles HTML templates and components into JavaScript files long before they are served to the client. With no templates to read and no risky client-side HTML or JavaScript evaluation, there are fewer opportunities for injection attacks.

You can also refer Angular’s official documentation link for understanding AOT here

15. How to create custom pipe in Angular ?

To create a custom pipe in Angular, you can follow these steps:

  1. Generate a new pipe: Use the Angular CLI to generate a new pipe using the `ng generate pipe` command. Open your terminal and navigate to your Angular project’s root directory, then run the following command:
ng generate pipe custom

This will create a new file `custom.pipe.ts` and add it to the appropriate directory in your project.

2. Implement the pipe:

Open the `custom.pipe.ts` file and implement your custom pipe logic within the `transform` method of the `CustomPipe` class. The `transform` method takes an input value and optional parameters, performs the desired transformation, and returns the result.

Here’s an example of a custom pipe that doubles a given number:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'custom'
})
export class CustomPipe implements PipeTransform {
transform(value: number): number {
return value * 2;
}
}

In this example, the `transform` method receives a number as input (`value`) and returns the result of doubling the input number (`value * 2`).

3. Register the pipe:

To use the custom pipe in your Angular application, you need to register it in the module where it will be used. Open the corresponding module file (e.g., `app.module.ts`) and import the `CustomPipe` class. Then, add the `CustomPipe` to the `declarations` array in the module’s decorator.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { CustomPipe } from './custom.pipe';

@NgModule({
declarations: [
AppComponent,
CustomPipe
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

4. Use the custom pipe:

Now that the custom pipe is registered, you can use it in your templates by referencing its name. For example, in your component’s template (`app.component.html`), you can use the custom pipe like this:

<h1>{{ 5 | custom }}</h1>

In this example, the `custom` pipe is applied to the value `5`, and the transformed result (10) will be displayed in the `<h1>` element. That’s it! You have created a custom pipe in Angular. You can now use the pipe to perform custom transformations on data within your templates.

16. What are inbuilt Angular pipes ?

Angular provides several built-in pipes that you can use out of the box to transform and format data in your Angular application. Here are some commonly used built-in Angular pipes:

1. DatePipe: Formats a date value according to the specified format.

<p>{{ today | date }}</p>
<p>{{ today | date: 'short' }}</p>

2. UpperCasePipe and LowerCasePipe: Converts a string to uppercase or lowercase.

<p>{{ 'Hello World' | uppercase }}</p>

<p>{{ 'Hello World' | lowercase }}</p>

3. DecimalPipe: Formats a number as a decimal according to the specified precision.

<p>{{ 3.14159 | number: '1.2-3' }}</p>

4. CurrencyPipe: Formats a number as a currency according to the specified currency code.

<p>{{ 1000 | currency: 'USD' }}</p>

5. PercentPipe: Formats a number as a percentage.

<p>{{ 0.75 | percent }}</p>

6. SlicePipe: Returns a portion of a string or array.

<p>{{ 'Hello World' | slice: 0:5 }}</p>

<p>{{ [1, 2, 3, 4, 5] | slice: 0:3 }}</p>

7. AsyncPipe: Handles asynchronous values by subscribing to an observable or promise and updates the view automatically when the value changes.

<p>{{ asyncData$ | async }}</p>

These are just a few examples of the built-in Angular pipes. Angular provides more pipes, such as `KeyValuePipe`, `JsonPipe`, `PercentPipe`, and more, each serving specific purposes. You can also create your own custom pipes as explained in the previous response.

17. Explain Software version nomenclature (semantic versioning) ?

Semantic Versioning, also known as SemVer, is a versioning scheme used for software projects to convey information about the compatibility, features, and changes in different releases of the software. It follows a specific format: `..`.

1. Major Version (`<major>`): The major version indicates significant changes that may introduce breaking changes or major updates to the software. This typically includes backward-incompatible changes, major new features, or significant architectural changes.

2. Minor Version (`<minor>`): The minor version represents backward-compatible additions or enhancements to the software. It includes new features or functionalities that are added without breaking existing functionality.

3. Patch Version (`<patch>`): The patch version indicates backward-compatible bug fixes, patches, or small updates that do not introduce any new features. These updates generally address issues, bugs, or security vulnerabilities in the software.

Here are some examples of semantic versioning:

— Version `1.0.0`: This is the initial release of the software, indicating that it has reached the stable state. Typically, the major version starts at `1` for the first stable release.

— Version `1.2.3`: This version indicates that there have been backward-compatible feature additions or enhancements (`1`) since the last release, along with backward-compatible bug fixes or patches (`2`), and minor bug fixes or small updates (`3`).

— Version `2.0.0`: This version signifies a major release that introduces backward-incompatible changes or major updates to the software.

Semantic Versioning helps developers and users understand the impact of updates and changes in software versions. It provides a consistent and standardized way to communicate the compatibility and significance of different releases, allowing developers to manage dependencies, handle upgrades, and ensure compatibility across projects.

It is worth noting that semantic versioning is not limited to software projects only. It can also be applied to libraries, APIs, frameworks, or any other project that follows a versioning scheme.

18. What is storybook in Angular ?

Please checkout the detailed explaination here

19. What are the design patterns in Angular ?

In Angular, which is a popular JavaScript framework for building web applications, several design patterns are commonly used to structure and organize code. These design patterns help developers create maintainable, scalable, and modular applications.

Here are some of the design patterns frequently utilized in Angular:

1. Singleton Pattern: Angular services are often implemented using the Singleton pattern. A service is instantiated once and shared across multiple components, allowing them to communicate and share data.

To implement the Singleton pattern in Angular, you can follow these steps:

a. Create a service using the Angular CLI:

ng generate service MySingletonService

b. There are two ways to create a single service in angular that is by using

-> providedIn property

-> NgModule providers arrays

c. Open the generated service file (`my-singleton-service.service.ts`) and modify it as follows:

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

@Injectable({
providedIn: 'root'
})
export class MySingletonService {
// Your service implementation goes here
}

d. The `providedIn: ‘root’` property in the `@Injectable` decorator is key to implementing the Singleton pattern in Angular. This tells Angular to provide the service at the root level, making it accessible throughout the application.

e. You can now use the `MySingletonService` in your components by injecting it into their constructors:

import { Component } from '@angular/core';
import { MySingletonService } from './my-singleton-service.service';

@Component({
selector: 'app-my-component',
template: '...',
})
export class MyComponent {
constructor(private mySingletonService: MySingletonService) {
// Access the shared service instance here
}
}

By injecting `MySingletonService` into multiple components, you will be accessing the same instance of the service across the application, ensuring data consistency and sharing.

It’s important to note that Angular itself manages the lifecycle of the singleton service. It creates and maintains a single instance of the service and shares it among components that request it.

In the case of NgModule providers array, a singleton service is created by passing the service as a value to the providers array and if the NgModule is root app module then the service will be available throughout the application as a singleton service.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { MySingletonService } from './my-singleton-service.service';
import { AppComponent } from './app.component';

@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [MySingletonService], // Add the service here
bootstrap: [AppComponent]
})
export class AppModule { }

That’s how you can implement the Singleton pattern in Angular using a service. This allows you to share data, maintain state, and provide centralized functionality throughout your application.

2. Dependency Injection (DI) Pattern: Angular utilizes the DI pattern to manage the dependencies between components and services. With DI, the required dependencies are provided to a component or service through constructor injection or property injection, promoting loose coupling and testability.

// Component using DI
constructor(private productService: ProductService) {
// Use the productService
}

3. Observer Pattern: Angular leverages the Observer pattern through the EventEmitter class and the RxJS library. Components can emit events using EventEmitters, and other components can subscribe to these events to react accordingly.

// Component emitting an event
@Output() productSelected = new EventEmitter();

selectProduct(product: Product) {
this.productSelected.emit(product);
}
// Component subscribing to an event

4. Strategy Pattern: The Strategy pattern enables you to dynamically select and switch between different strategies at runtime based on specific conditions or requirements. By encapsulating these behaviors in separate classes, components can switch between strategies based on specific conditions.

Here’s an example of implementing the Strategy pattern in Angular:

a. Define an interface that represents the common behavior of the strategies. Let’s assume we have a payment processing scenario:

// payment-strategy.interface.ts
export interface PaymentStrategy {
processPayment(amount: number): void;
}

b. Implement multiple strategies by creating separate classes that implement the `PaymentStrategy` interface. Each class will provide its own implementation of the `processPayment` method:

// credit-card-strategy.ts
export class CreditCardStrategy implements PaymentStrategy {
processPayment(amount: number): void {
console.log(`Processing credit card payment of $${amount}`);
// Perform credit card payment processing logic here
}
}

// paypal-strategy.ts
export class PaypalStrategy implements PaymentStrategy {
processPayment(amount: number): void {
console.log(`Processing PayPal payment of $${amount}`);
// Perform PayPal payment processing logic here
}
}

c. Create a context class that will use the strategies and provide a method to set the active strategy:

// payment-context.ts
import { PaymentStrategy } from './payment-strategy.interface';

export class PaymentContext {
private strategy: PaymentStrategy;
setStrategy(strategy: PaymentStrategy): void {
this.strategy = strategy;
}
processPayment(amount: number): void {
this.strategy.processPayment(amount);
}
}

d. Now, you can utilize the strategies in your Angular components or services. For example:

import { Component } from '@angular/core';
import { PaymentContext } from './payment-context';
import { CreditCardStrategy } from './credit-card-strategy';
import { PaypalStrategy } from './paypal-strategy';

@Component({
selector: 'app-payment-component',
template: '...',
})
export class PaymentComponent {
constructor(private paymentContext: PaymentContext) {}
processCreditCardPayment(amount: number): void {
this.paymentContext.setStrategy(new CreditCardStrategy());
this.paymentContext.processPayment(amount);
}
processPaypalPayment(amount: number): void {
this.paymentContext.setStrategy(new PaypalStrategy());
this.paymentContext.processPayment(amount);
}
}

e. In this example, the `PaymentComponent` uses the `PaymentContext` to switch between different payment strategies (`CreditCardStrategy` and `PaypalStrategy`) based on user actions or conditions. By setting the active strategy through `setStrategy`, you can dynamically change the behavior of the payment processing logic in `processPayment`.

This implementation allows for easy extensibility, as you can add new strategies by implementing the `PaymentStrategy` interface and use them interchangeably within the `PaymentComponent` or any other component that requires payment processing functionality.

The Strategy pattern provides flexibility and maintainability by separating the implementation of different algorithms or behaviors from the client code, allowing you to change or extend strategies without modifying existing code.

5. Decorator Pattern: Angular decorators, such as @Component and @Injectable, are based on the Decorator pattern. Decorators provide a way to enhance or modify the behavior of classes or class members without directly modifying the underlying code.

a. Create a base component that represents the core functionality:

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

@Component({
selector: 'app-base-component',
template: 'Base Component',
})
export class BaseComponent {}

b. Create a decorator component that extends the base component:

import { Component, ViewChild } from '@angular/core';
import { BaseComponent } from './base-component';

@Component({
selector: 'app-decorator',
template: `
<div>
<p>This is the decorator component</p>
<ng-content></ng-content>
</div>
`,
})
export class DecoratorComponent extends BaseComponent {}

In this example, the `DecoratorComponent` is a child component that extends the functionality of the `BaseComponent`. It wraps the `BaseComponent` within itself and adds extra content using `<ng-content>`. This allows you to inject additional behavior or template content around the base component.

c. Use the decorator component in your application:

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

@Component({
selector: 'app-root',
template: `
<app-decorator>
<app-base-component></app-base-component>
</app-decorator>
`,
})
export class AppComponent {}

In the `AppComponent` template, the `BaseComponent` is wrapped within the `DecoratorComponent` using its selector `<app-decorator>`. You can inject other components, templates, or HTML content within the `DecoratorComponent` to extend or modify the behavior of the `BaseComponent`.

By using the Decorator pattern in Angular, you can dynamically extend or modify the functionality of existing components by wrapping them within decorator components. This approach provides flexibility, code reusability, and maintainability, as you can reuse the base components while adding specific behavior or content as needed.

6. Facade Pattern:The Facade pattern is a structural design pattern that provides a simplified interface to a complex subsystem, making it easier to use and understand. In Angular, you can apply the Facade pattern to create a simplified API or service that encapsulates the complexity of interacting with multiple components, services, or modules.

Here’s an example of implementing the Facade pattern in Angular:

a. Identify a complex subsystem or set of related components/services that you want to simplify for client usage.

b. Create a Facade service that encapsulates the interactions with the complex subsystem. The Facade service will provide a simplified interface for clients to access the subsystem’s functionality.

import { Injectable } from '@angular/core';
import { ComplexServiceA } from './complex-service-a';
import { ComplexServiceB } from './complex-service-b';

@Injectable()
export class FacadeService {
constructor(private serviceA: ComplexServiceA, private serviceB: ComplexServiceB) {}
// Provide simplified methods that internally call the appropriate complex subsystem methods
performOperation(): void {
this.serviceA.complexOperationA();
this.serviceB.complexOperationB();
}
}

c. Implement the complex subsystem components/services that the Facade service interacts with. These components/services handle the actual complex logic.

@Injectable()
export class ComplexServiceA {
complexOperationA(): void {
// Complex logic of service A
console.log('Performing complex operation A');
}
}

@Injectable()
export class ComplexServiceB {
complexOperationB(): void {
// Complex logic of service B
console.log('Performing complex operation B');
}
}

d. Use the Facade service in your components to simplify the usage of the complex subsystem:

import { Component } from '@angular/core';
import { FacadeService } from './facade.service';

@Component({
selector: 'app-client-component',
template: '...',
})
export class ClientComponent {
constructor(private facadeService: FacadeService) {}
performFacadeOperation(): void {
this.facadeService.performOperation();
}
}

e. In this example, the `ClientComponent` utilizes the `FacadeService` to perform complex operations without needing to interact directly with the complex subsystem (`ComplexServiceA` and `ComplexServiceB`). The `FacadeService` encapsulates the complexity and provides a simplified interface for the client component to interact with.

By using the Facade pattern in Angular, you can simplify the usage of complex subsystems, hide their implementation details, and provide a straightforward and easy-to-use interface for clients. This promotes code maintainability, readability, and modularity by abstracting the complexity of interacting with multiple components or services behind a single facade.

7. Composite Pattern: The Composite Design Pattern is a structual design pattern that is used to compose objects into a tree-like structure. Components can be composed of other components, forming a tree-like structure. This pattern enables the creation of reusable and hierarchical UI components.

In Angular, you can apply the Composite pattern to represent hierarchical relationships between components or services.

Here’s an example of implementing the Composite pattern in Angular:

a. Create an abstract class or interface that represents the common behavior for both individual objects and groups:

// component.interface.ts
export interface ComponentInterface {
operation(): void;
}

b. Implement the abstract class or interface for individual objects:

// leaf.component.ts
import { ComponentInterface } from './component.interface';

export class LeafComponent implements ComponentInterface {
operation(): void {
console.log('Performing operation on a leaf component.');
}
}

c. Implement the abstract class or interface for the composite object, which can contain both individual objects and other composite objects:

// composite.component.ts
import { ComponentInterface } from './component.interface';

export class CompositeComponent implements ComponentInterface {
private children: Component[] = [];
add(component: ComponentInterface): void {
this.children.push(component);
}
remove(component: ComponentInterface): void {
const index = this.children.indexOf(component);
if (index > -1) {
this.children.splice(index, 1);
}
}
operation(): void {
console.log('Performing operation on the composite component.');
for (const child of this.children) {
child.operation();
}
}
}

d. Use the composite object to create a tree-like structure of components:

import { ComponentInterface } from './component.interface';
import { LeafComponent } from './leaf.component';
import { CompositeComponent } from './composite.component';

// Create leaf components
const leaf1: ComponentInterface = new LeafComponent();
const leaf2: ComponentInterface = new LeafComponent();
// Create composite component
const composite: ComponentInterface = new CompositeComponent();
composite.add(leaf1);
composite.add(leaf2);
// Create another composite component
const composite2: ComponentInterface = new CompositeComponent();
composite2.add(composite);
composite2.add(leaf1);
// Perform operation on the composite structure
composite2.operation();

e. In this example, we create a tree-like structure using the Composite pattern. The `CompositeComponent` can contain both individual `LeafComponent` objects and other `CompositeComponent` objects. Calling the `operation()` method on the top-level `CompositeComponent` will recursively invoke the operation on all its children, whether they are leaf components or other composite components.

By using the Composite pattern in Angular, you can represent complex hierarchical relationships between components or services in a uniform manner. It allows you to treat individual objects and groups of objects in a consistent way, simplifying the code and enabling recursive operations on the composite structure.

8.Factory Pattern: The Factory pattern is a creational design pattern that provides an interface for creating objects without specifying the exact class of the object that will be created. In Angular, you can apply the Factory pattern to encapsulate object creation logic and provide a centralized place for creating instances of different classes.

Here’s an example of implementing the Factory pattern in Angular:

a. Define an abstract class or interface that represents the common behavior of the objects you want to create:

// product.interface.ts
export interface Product {
operation(): void;
}

b. Implement multiple classes that conform to the `Product` interface:

// product-a.ts
export class ProductA implements Product {
operation(): void {
console.log('Product A operation.');
}
}

// product-b.ts
export class ProductB implements Product {
operation(): void {
console.log('Product B operation.');
}
}

c. Create a factory class that encapsulates the object creation logic:

// product-factory.ts
import { Product } from './product.interface';
import { ProductA } from './product-a';
import { ProductB } from './product-b';

export class ProductFactory {
createProduct(type: string): Product {
if (type === 'A') {
return new ProductA();
} else if (type === 'B') {
return new ProductB();
}
throw new Error('Invalid product type');
}
}

d. Use the factory class to create instances of the desired products:

import { Component } from '@angular/core';
import { ProductFactory } from './product-factory';
import { Product } from './product.interface';

@Component({
selector: 'app-example',
template: '...',
})
export class ExampleComponent {
constructor(private productFactory: ProductFactory) {}
createProduct(type: string): void {
const product: Product = this.productFactory.createProduct(type);
product.operation();
}
}

e. In this example, the `ExampleComponent` uses the `ProductFactory` to create instances of different products based on the provided type. By calling the `createProduct` method with the desired type (‘A’ or ‘B’), it receives an instance of the corresponding product class and can invoke its `operation()` method.

Using the Factory pattern in Angular provides a centralized place for creating objects and decouples the client code from the concrete classes. It allows for flexible object creation and enables easy extensibility by adding new product classes and updating the factory logic accordingly.

These are some of the design patterns commonly used in Angular. However, it’s worth noting that Angular itself follows the MVC (Model-View-Controller) architectural pattern, where components serve as the controllers, templates represent views, and services act as models.

20. What are the disadvantages of AOT ?

The main limitation is that AoT, due to the way it compiles the raw code, cannot be used with common code patterns, for example, default exports from modules, template literals for templates, and functions in providers, routes, or declarations.

AoT Do’s and Don’ts

This section explains the cases listed above, and will show how each of them fails and works.

-> arrow-function-exports

Arrow function does not work with AoT when it is passed to an NgModule.


Don't:

export const couterReducer = (state, action: Action) => {
// ...
}

Do:

export function counterReducer(state, action: Action) {
// ...
}

-> control

This is used as a simplest working case. default-exports Default exports are not supported with AoT.

default-exports

Default exports are not supported with AoT.


Don't:

export default class AppComponent {};

Do:

export class AppComponent {};

-> form-control

Use this.helloForm.controls["greetingMessage"] to retrieve form control is fine.

-> form-control-error

The syntax errors? is not supported by AoT.


Don't:

{{helloForm.controls["greetingMessage"].errors?.minlength}}

Do:

{{helloForm.controls["greetingMessage"].hasError("minlength")}}

-> func-in-routes

Direct use of function in route is not supported by AoT. Either avoid using it or export it from other module.


Don't:

function random() {
return [{
path: "",
component: AppViewComponent
}];
}
const SAMPLE_APP_ROUTES: Routes = random();

Do:

const SAMPLE_APP_ROUTES: Routes = [{
path: "",
component: AppViewComponent
}];

For more details click here

21. What is the use of tilde(~) and caret(^) sign in package.json ?

Caret sign


"dependencies": {
"express": "^3.9.2"
}

Caret allows:-

->Backward compatible new functionalities
->Large internal refactor
->Bug fixes
->Deprecation of old functionality (which is still operational)
->With the caret you can get releases like 3.., where the * characters will match the highest version number available. So changes in the major digit, like 4.0.0, will not be used in this case.

Tilde sign


"dependencies": {
"express": "~3.9.2"
}

Tilde allows

->Bug fixes
->With tilde, you can get releases like 3.9.*. Only the latest bug fixes are allowed with the tilde.

So we can conclude by saying that the ~ character should be used if you want to lock in the patch number. You should use this when you are ready to accept only bug-fixes and don’t want to face any possibly incompatible alterations. On the other hand, the ^ character is responsible for locking in the patch and the minor version numbers. It’s to be used when you want to have backwards compatible new functionality as well as bug fixes.

22. What are interceptors in Angular ?

In Angular, interceptors are classes that can be used to intercept and manipulate HTTP requests and responses. They provide a way to modify or handle HTTP requests globally before they are sent to the server or to modify the HTTP responses before they are delivered to the calling code. Interceptors are useful for tasks like adding authentication headers, logging, error handling, caching, and more.

To create an interceptor in Angular, you need to implement the HttpInterceptor interface and define the logic for intercepting requests and responses.

Here’s an example of an HTTP interceptor that adds an authorization header to outgoing requests:

  1. Create the interceptor class:

// auth-interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(
request: HttpRequest,
next: HttpHandler
): Observable> {
// Add authorization header to the request
const authToken = 'your_auth_token_here';
const authRequest = request.clone({
setHeaders: { Authorization: `Bearer ${authToken}` },
});

// Pass the modified request to the next interceptor or the HTTP handler
return next.handle(authRequest);
}
}

2. Register the interceptor:

To use the interceptor, you need to provide it in the AppModule or the module where your HTTP requests are made.


// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth-interceptor';

@NgModule({
imports: [BrowserModule, HttpClientModule],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
],
})
export class AppModule {}

In this example, we register the AuthInterceptor as a provider for the HTTP_INTERCEPTORS multi-provider token. The `multi: true` option indicates that this interceptor can be one of many, as multiple interceptors can be provided.

Now, whenever an HTTP request is made in your application, the AuthInterceptor will intercept the request, add the authorization header, and pass it on to the next interceptor or the actual HTTP handler. This way, you can centralize common HTTP request-related tasks and keep your code clean and maintainable.

23. Can we rename dist folder in Angular Project ?

In angular.json file change value of outputPath property


{
"projects": {
"my-app-name": {
"architect": {
"options": {
"outputPath": "dist/my-app-name",

24. How would the browser Know that your app is an Angular based app ?

getAllAngularRootElements() on browse console will return something .For now it is returing :-[app-root]

25. How to create a custom decorator in Angular ?

Decorators are a design pattern that is used to separate modification or decoration of a class without modifying the original source code. In Angular, decorators are functions that allow a service, directive or filter to be modified prior to its usage.

Create decorator


function log(target,name,descriptor) {
const original=descriptor.value;
descriptor.value=function(...args) {
console.log('this function is hacked')
const result=original.apply(this,args)
console.log("the result of the function is ", result);
return result;
}
original();
return descriptor;
}

Usage of decorator

  @log
sum(a,b) {
return a+b;
}
//function overridden by decorator called
sum(2,3)

//output will be
this function is hacked
the result of the function is 5

26. How to make multiple http calls in parallel in Angular ?

This can be achieved by using forkJoin, this operator takes an array of observables and waits for all the source observables to complete. Once they all complete, it emits an array of the last emitted values from each observable. Example:


import { forkJoin, of, throwError } from 'rxjs';

const observables = [
of(1,2,3).pipe(delay(500)),
from([10,11,12])
]

const $forkJoin = forkJoin(observables);

$forkJoin.subscribe(data=>{
console.log('forkjoin data', data); // [3,12] as forkJoin will return last emitted values of each observable
})

In this example, `forkJoin` takes an array of observables, including two observables that emit ‘A’ and ‘B’ respectively after a delay, and an observable that throws an error after a delay. `forkJoin` waits for all the observables to complete, and once they complete, it emits an array of the last emitted values from each observable. However, if any of the observables in `forkJoin` throws an error, the error will be propagated to the error callback of the `subscribe` method.

27. What is a module in TypeScript, and how can you use it ?

In TypeScript, a module is a way to organize code into reusable, self-contained units of code that can be imported and exported between different parts of an application. Modules can contain classes, functions, interfaces, and other code, and can be either internal to a project or external libraries.

To use a module in TypeScript, you need to define it using the `export` keyword, which makes its members available to other parts of the application. You can then import the module using the `import` keyword, which allows you to use its members in your code.

Here is an example of how to define and use a module in TypeScript:

// myModule.ts
export function myFunction() {
// code here
}

export class MyClass {
// code here
}

In this example, we define a module called `myModule` that exports a function called `myFunction` and a class called `MyClass`. The `export` keyword makes these members available outside of the module.

To use the members of the `myModule` module in another file, you can import them using the `import` keyword:

// main.ts
import { myFunction, MyClass } from "./myModule";

myFunction();
const myInstance = new MyClass();

In this example, we import the `myFunction` function and `MyClass` class from the `myModule` module using destructuring. We can then call the `myFunction` function and create an instance of the `MyClass` class, both using the imported names.

There are different ways to import and export modules in TypeScript, such as importing all members using the `* as` syntax, importing default exports, or using aliases for imported members. It is important to understand the different syntaxes and their implications, depending on the size and complexity of the project.

Using modules can help you write more modular and maintainable code in TypeScript, by isolating functionality and reducing naming conflicts. However, it is important to use them judiciously and not to create too many small modules, which can increase the complexity of the codebase.

28. How to hit an API before the loading of the appComponent ?

The package @angular/router has the Resolve property for routes. So you can easily resolve data before rendering a route view. The following example implements a resolve() method that retrieves the data needed to activate the requested route.

@Injectable({ providedIn: 'root' })
export class HeroResolver implements Resolve {
constructor(private service: HeroService) {}

resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable|Promise|any {
return this.service.getHero(route.paramMap.get('id'));
}
}

Here, the defined resolve() function is provided as part of the Route object in the router configuration:

@NgModule({
imports: [
RouterModule.forRoot([
{
path: 'detail/:id',
component: HeroDetailComponent,
resolve: {
hero: HeroResolver
}
}
])
],
exports: [RouterModule]
})
export class AppRoutingModule {}

29. If there is a package(or say library) that is not available through NPM , then how would you use it in your angular application ?

For anything that doesn’t have an npm package, you’ll have to download the file and put it somewhere in your project — I’d recommend putting it in a directory called vendor or lib. The import statement can use a relative path to the module you want to use, so it should be straightforward, e.g. if you put your third-party module in vendor/some-lib.js, you would import it with:

Code e.g

// src/foo.js
import './../vendor/some-lib';
If you want to get fancy, you can use resolve.alias in your webpack config so that you never have to work out the relative path.

// webpack.config.js
const path = require('path');
// ...
resolve: {
alias: {
vendor: path.resolve(__dirname, 'vendor')
}
},
// src/foo.js
import 'vendor/some-lib';

30. How to implement treeshaking in Angular ?

Tree shaking is a dead code elimination process that identifies and removes unused modules from the final production bundle. This technique is particularly essential in large-scale applications where developers often include various libraries and dependencies. By eliminating unused code, tree shaking helps optimize the bundle size, resulting in a more efficient application.

Angular, being a popular front-end framework, leverages tree shaking to enhance the performance of applications. It relies on the underlying build tools, such as Webpack, to analyze the code and eliminate any portions that are not being utilized.

Example of Tree Shaking in Angular:

When a service is injected using the ‘providedIn’ property of the @Injectable decorator, the service will only be injected into the module when explicitly requested. If the module does not request the service, the tree shaker will exclude it. The use of ‘providedIn’ allows us to specify to Angular the module in which our service should be registered.

// logger.service.ts
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root',
})
export class LoggerService {
log(message: string): void {
console.log(message);
}
}

During the build process, Angular’s build tools, along with Webpack, will perform tree shaking and eliminate the unused code. Tree shaking ensures that the final bundle only includes the code that is actively being used, resulting in a smaller bundle size. This is crucial for optimizing the performance of your Angular application, especially as the codebase grows.

Configuration for Tree Shaking in Angular:

While Angular itself supports tree shaking, it’s essential to configure your project properly to enable this optimization. Here are some key steps:

  1. Use Production Mode: Ensure that you build your Angular application in production mode. This can be achieved by running the following command:
  2. Webpack Configuration: Angular projects often use Webpack as the underlying build tool. Make sure your Webpack configuration is set up to enable tree shaking. The default Angular CLI configuration already includes necessary settings for tree shaking.

Conclusion:

In conclusion, tree shaking is a valuable optimization technique in Angular that helps reduce the size of your application bundle by eliminating unused code. As demonstrated in the example, Angular’s build tools, along with Webpack, work together to analyze and remove dead code during the production build process. By incorporating tree shaking into your Angular projects, you can significantly enhance the performance and loading times of your applications, providing a smoother user experience.

31. What can be the values of ‘providedIn’ property of @injectable decorator ?

@injectable decorator can have following values :

  1. ‘providedIn’: root — It means that the service is provided in the root injector of the application and is accessible in all modules and components of the application. Even if the application has lazy loaded modules , same serivce instance would be shared with them too.
  2. ‘providedIn’: moduleClassName — It means that service is provided in the injector of the specific module whose name is specified against ‘providedIn’ key. Hence it would be accessible at that perticular module level.
  3. ‘provideIn’: any — It means that the service would be present in the root injector of the application . Although , if there are lazy loaded modules in the application then they would get there own instance of the service.
  4. ‘providedIn’: platform — It can be used when there are multiple angular elements ( angular web components) in a single page , and we want the same inastance of the service to be shared across all the angular elements.

32. How to optimize Angular application using OnPush change detection strategy ?

The `OnPush` change detection strategy in Angular is designed to optimize performance by reducing the number of change detection cycles. It is based on the concept of immutability and relies on input properties and explicit change detection triggering.

To optimize an Angular application using the `OnPush` strategy, follow these steps:

Let’s assume we have a parent component called `ParentComponent` and a child component called `ChildComponent`. The child component receives an array of items as an input property and displays them in a list. We’ll optimize this scenario using the `OnPush` strategy.

  1. Use the `OnPush` change detection strategy in components:
// parent.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-parent',
template: `
<app-child [items]="items"></app-child>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent {
items: string[] = ['Item 1', 'Item 2', 'Item 3'];
addItem() {
this.items.push('New Item'); // Incorrect way to update the array
}
}
// child.component.ts
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-child',
template: `
<ul>
<li *ngfor="let item of items">{{ item }}</li>
</ul>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
@Input() items: string[];
}

In the above code, both the `ParentComponent` and `ChildComponent` are using the `OnPush` change detection strategy.

2. Use immutable data for input properties:

// parent.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-parent',
template: `
<app-child [items]="items"></app-child>
<button (click)="addItem()">Add Item</button>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent {
items: string[] = ['Item 1', 'Item 2', 'Item 3'];
addItem() {
this.items = [...this.items, 'New Item']; // Correct way to update the array using spread operator
}
}

In the `ParentComponent`, when adding a new item to the `items` array, we create a new array using the spread operator `[…this.items]` and then add the new item. This ensures that a new reference is created, which triggers change detection in the `ChildComponent` when the input property changes.

Conclusion :

By applying these optimization techniques, you can enhance the performance of your Angular application with the `OnPush` change detection strategy. Immutable data help minimize unnecessary change detection cycles, resulting in improved efficiency and responsiveness.

33. What is the latest Angular version and what are the new features added in it ?

At the time of writing i.e Feb 2024, Latest Angular version is Angular 17. Please find the details of it’s features on this link :https://blog.angular.io/introducing-angular-v17-4d7033312e4b

34. What are the types of forms available in Angular ? Explain with syntax.

In Angular, there are different types of forms available for handling user input and performing validation. The two main types of forms in Angular are Template-driven forms and Reactive forms.

  1. Template-driven Forms:

— Template-driven forms are primarily defined within the HTML template of the component using Angular directives.

— The form controls and validation rules are inferred from the template, reducing the need for explicit form control declaration in the component code.

— Template-driven forms are suitable for simple forms with basic validation requirements.

Syntax:

<form #myform="ngForm" (ngsubmit)="onSubmit()">
<label for="name">Name:</label>
<input type="text" id="name" name="name" ngmodel="" required="">

<label for="email">Email:</label>
<input type="email" id="email" name="email" ngmodel="" required="" email="">

<button type="submit">Submit</button>
</form>

In the example above, `ngForm` is a directive that represents the entire form. Each input element uses the `ngModel` directive for two-way data binding and includes additional directives like `required` and `email` for validation.

2. Reactive Forms:

— Reactive forms are created programmatically in the component class using TypeScript.

— Form controls are explicitly defined in the component code, providing more control and flexibility.

— Reactive forms are suitable for complex forms with dynamic validation requirements and advanced interactivity.

Syntax:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
selector: 'app-my-form',
template: `
<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<label for="name">Name:</label>
<input type="text" id="name" formControlName="name">

<label for="email">Email:</label>
<input type="email" id="email" formControlName="email">

<button type="submit">Submit</button>
</form>
`,
})
export class MyFormComponent implements OnInit {
myForm: FormGroup;
ngOnInit() {
this.myForm = new FormGroup({
name: new FormControl('', Validators.required),
email: new FormControl('', [Validators.required, Validators.email]),
});
}
onSubmit() {
if (this.myForm.valid) {
// Handle form submission
}
}
}

In the example above, `FormGroup` represents the entire form, while `FormControl` represents individual form controls. Validators are applied to each form control to define validation rules.

Conclusion:

These are the main types of forms available in Angular: Template-driven forms and Reactive forms. Depending on the complexity and requirements of your form, you can choose the appropriate form type for your Angular application.

35. What are dynamic forms and how to create them in Angular ?

Dynamic forms in Angular allow you to create forms dynamically at runtime, where the form structure and controls are determined dynamically based on data or user interactions. This is particularly useful when dealing with forms that have a varying number of fields or when the form structure needs to be generated dynamically.

To create dynamic forms in Angular, you can follow these steps:

  1. Define the data model: Start by defining the data model that represents the form fields and their properties. This can be done using classes or interfaces in TypeScript.
  2. Create a form group: In the component class, create a `FormGroup` instance that will hold the dynamic form controls. You can use the `FormBuilder` service to simplify the creation of the form group.
  3. Add form controls dynamically: Based on your requirements or data, dynamically add form controls to the form group. This can be done using methods such as `addControl()` or `setControl()` on the form group.
  4. Generate form controls in the template: In the component’s template, iterate over the form controls in the form group and generate the corresponding input fields or controls dynamically using directives like `ngFor`.
  5. Handle form submission: Implement the logic to handle form submission in the component, using the `FormGroup` instance to access the form values and perform any necessary operations.

Here’s a basic example illustrating the creation of a dynamic form in Angular:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
})
export class DynamicFormComponent implements OnInit {
dynamicForm: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
// Create an empty form group
this.dynamicForm = this.formBuilder.group({});

// Add dynamic form controls
this.addFormControl('name', Validators.required);
this.addFormControl('email', [Validators.required, Validators.email]);
}
addFormControl(fieldName: string, validators: any[] = []) {
this.dynamicForm.addControl(fieldName, this.formBuilder.control('', validators));
}
onSubmit() {
if (this.dynamicForm.valid) {
const formValues = this.dynamicForm.value;
// Handle form submission
}
}
}

In the above example, the `dynamicForm` is a `FormGroup` created using the `FormBuilder`. The `addFormControl()` method is used to dynamically add form controls to the `dynamicForm` based on the field name and validation rules. The form controls are generated in the template using `ngFor` to iterate over the form group’s controls.

By following these steps, you can create dynamic forms in Angular that adapt to changing requirements or data dynamically.

36. How to show error messages on form controls ?

Refer the following link for form control error messages — How to Display Validation or Error Messages in Angular Forms

37. How to use a service only for a specific component instead of the whole module ?

This can be achieved by putting the service name in the providers array of component’s decorator instead of putting the service name in providers array of module’s decorator , also don’t provide the property ‘provided in : root’ in the service’s decorator .

38. Can you put ngIf and ngFor on same element ?

From angular version 2 and above we cannot put more than 1 structural directive on 1 element.If we have to use ngIf and and ngFor together than we can put one of them inside ng-container.

39. What’s the difference between Observable and Subject ?

Following are the difference between Observable and Subject :

  1. syntax for creating an observsble and a subject is different

Observable:

let source = Observable.create((observer) => {
setInterval(observer.next(Math.random()) ,100)
})
let target = source.subscribe((data) => console.log(data));

Subject:

let source = new Subject();
let target = source.subscribe((data) => console.log(data));

2. Subjects are multicasting whereas Observables are unicasting i.e. Subject provide same data to all it’s subscribers , whereas for an observable when a new subscriber is added then the observable is executed again and a new data stream is created , so the different subscribers get different data. 3. Observables are cold by default (since the data source of observable is withing the observable only as we can see in the above syntax). Subjects are not cold. for detailed differences visit the following youtube links :

40. How does ng serve work ?

Basically ng serve command builds and serve the application. It rebuilds the application if changes occur. for more detailed description , please go through this youtube video How Angular Works Internally

41. How to improve Angular app performance ?

These are a few essential hacks that can help to significantly improve the Angular app performance :

  1. Using AoT Compilation.
  2. Using OnPush Change Detection Strategy.
  3. Using Pure Pipes.
  4. Unsubscribe from Observables
  5. Lazy Loading.
  6. Use trackBy option for For Loop.
  7. Usage of Web Workers.

42. What is AuthGuard in Angular ?

In Angular, Auth Guards are used to protect routes and determine whether a user is allowed to access a specific route or not based on their authentication status or user role. Auth Guards are implemented as services and are typically used in conjunction with Angular’s routing system.

Here’s an example to demonstrate how Auth Guards work in Angular:

  1. Create an Auth Guard service:
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(): boolean {
// Check the user's authentication status or role
const isAuthenticated = /* your authentication check */;
const userRole = /* get user role */;
if (isAuthenticated && userRole === 'admin') {
return true; // Allow access to the route
} else {
this.router.navigate(['/login']); // Redirect to login page or unauthorized page
return false; // Deny access to the route
}
}
}

2. Define routes in the app module:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home.component';
import { AdminComponent } from './admin.component';
import { LoginComponent } from './login.component';
import { AuthGuard } from './auth.guard';

const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'admin', component: AdminComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

In this example, we have three routes: the home route, the admin route, and the login route. The admin route is protected by the `AuthGuard` by setting the `canActivate` property to `[AuthGuard]`.

3. Implement the protected component:

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

@Component({
selector: 'app-admin',
template: 'Admin Page'
})
export class AdminComponent { }

4. Use the Auth Guard in the template or component:

<!-- Example of using Auth Guard in a template -->
<button [routerlink]="['/admin']" *ngif="isAuthenticated">Go to Admin</button>

<!-- Example of using Auth Guard in a component -->
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-some-component',
template: `
<button (click)="goToAdmin()" *ngif="isAuthenticated">Go to Admin</button>
`
})
export class SomeComponent {
isAuthenticated: boolean;
constructor(private router: Router) {}
goToAdmin() {
if (this.isAuthenticated) {
this.router.navigate(['/admin']);
}
}
}

In both examples above, the Auth Guard is used to conditionally display or navigate to the admin route based on the user’s authentication status. If the user is authenticated and has the appropriate role (in this case, ‘admin’), they are granted access to the route. Otherwise, they are redirected to the login page or an unauthorized page.

Conclusion :

Auth Guards play a crucial role in securing routes and controlling access to different parts of an Angular application based on authentication and authorization rules. By implementing and utilizing Auth Guards, you can ensure that certain routes are protected and only accessible to authorized users.

43. Explain the canActivateChild route guard ?

The canActivateChild route guard in Angular allows you to check if a user is allowed to activate child routes. It is used to protect child routes of a particular route from being activated if certain conditions are not met.

When a user navigates to a child route, Angular checks if there is an associated canActivateChild guard in the parent route’s route configuration. If there is, Angular executes the guard before activating the child route.

The canActivateChild guard is implemented as a service that implements the CanActivateChild interface. This interface has a single method, canActivateChild(), which returns a boolean or a promise that resolves to a boolean. If the method returns true, the child route is activated. If it returns false or a promise that resolves to false, the child route is not activated, and the user is redirected to a different route, or a custom error page is displayed.

Here is an example of how to use the canActivateChild route guard:

import { Injectable } from '@angular/core';
import { CanActivateChild, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivateChild {
canActivateChild(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable | Promise | boolean {
// Check if the user is authenticated
if (this.authService.isAuthenticated()) {
return true;
} else {
// If the user is not authenticated, redirect to the login page
this.router.navigate(['/login']);
return false;
}
}
}

In this example, we have an AuthGuard service that implements the CanActivateChild interface. The canActivateChild() method checks if the user is authenticated using a method isAuthenticated() provided by an AuthService. If the user is authenticated, the method returns true, allowing the child route to be activated. If the user is not authenticated, the method navigates to the login page and returns false, preventing the child route from being activated.

To use the AuthGuard service, you can add it to the canActivateChild property in the route configuration for the parent route that guards its child routes:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from './auth.guard';
import { ParentComponent } from './parent.component';
import { ChildComponent } from './child.component';

const routes: Routes = [
{
path: 'parent',
component: ParentComponent,
canActivateChild: [AuthGuard],
children: [
{
path: 'child',
component: ChildComponent
}
]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

In this example, the canActivateChild property is set to an array containing the AuthGuard service. This guards the child route with the AuthGuard.

Still confused? if yes, check link canActivateChild — tektutorialshub for explanation

44. What is the difference between Canload and canActivate route guards ?

The CanLoad Guard checks the loading of the Lazy Loaded Module.We generally use this guard when we do not want unauthorized user to navigate to any of the routes of the module and also stop then even see the source code of the module.

CanActivate Guard, prevents unauthorized user from accessing the route. But it does not stop the module from being downloaded. The user can use the chrome developer console to see the source code.

45. Explain switch map , mergemap , forkjoin, combineLatest, concatMap, exhaustMap . what would happen if any of the requests fails in switch map , merge map or forkjoin ?

Let’s go through each operator and explain them along with examples. We’ll also discuss what happens if any of the requests fail when using `switchMap`, `mergeMap`, or `forkJoin`.

  1. switchMap: This operator is used to map each source value to an inner observable, and it only emits the values from the most recent inner observable. If a new source value arrives before the previous inner observable completes, it will switch to the new inner observable and unsubscribe from the previous one.

Example:

import { of, interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';
const $switchMap = from([1,2,3,4]).pipe(switchMap(data=>{
return of(data).pipe(delay(500))
}));

$switchMap.subscribe(data=>{
console.log('switch map data', data); // 4 as switchMap cancels all previous observables when new observable is emitted
})

In this example, `sourceObservable` emits values every second. For each value emitted, `switchMap` creates an inner observable using `from` operator and emits the value from the source observable after a delay of one second. If a new value is emitted before the previous inner observable completes, it switches to the new inner observable and cancels the previous one. Therefore, only the most recent inner observable value will be emitted.

2. mergeMap: This operator maps each source value to an inner observable and merges the values from multiple inner observables into a single observable. It does not cancel or unsubscribe from any inner observables.

Example:

import { of } from 'rxjs';
import { mergeMap, delay } from 'rxjs/operators';

// Create an observable that emits three values
const sourceObservable = of(1, 2, 3);
// Use mergeMap to merge the values from the inner observables
const resultObservable = sourceObservable.pipe(
mergeMap((value) => {
// Create an inner observable that emits the value after a delay
return of(value).pipe(delay(1000));
})
);
// Subscribe to the result observable
resultObservable.subscribe((value) => {
console.log(value); // 1 2 3
});

In this example, `sourceObservable` emits three values: 1, 2, and 3. For each value emitted, `mergeMap` creates an inner observable using `of` operator and emits the value after a delay of one second. Since `mergeMap` does not cancel or switch between inner observables, all the values from each inner observable will be merged into a single observable and emitted in the order they complete.

3. forkJoin: This operator takes an array of observables and waits for all the source observables to complete. Once they all complete, it emits an array of the last emitted values from each observable.

Example:

import { forkJoin, of, throwError } from 'rxjs';

const observables = [
of(1,2,3).pipe(delay(500)),
from([10,11,12])
]
const $forkJoin = forkJoin(observables);
$forkJoin.subscribe(data=>{
console.log('forkjoin data', data); // [3,12] as forkJoin will return last emitted values of each observable
})

In this example, `forkJoin` takes an array of observables, including two observables that emit ‘A’ and ‘B’ respectively after a delay, and an observable that throws an error after a delay. `forkJoin` waits for all the observables to complete, and once they complete, it emits an array of the last emitted values from each observable. However, if any of the observables in `forkJoin` throws an error, the error will be propagated to the error callback of the `subscribe` method.

4. combineLatest: This operator combines the latest values from multiple observables into a single observable. It emits an array of the latest values whenever any of the source observables emit a new value.

Example:

import { combineLatest, interval } from 'rxjs';

const observables = [
of(1,2,3,4),
from([10,11,12])
]

const $combineLatest = combineLatest(observables);
$combineLatest.subscribe(data=> {
console.log('combineLatest data', data);
})
/* output */
// [4, 10]
// [4,11]
// [4,12]

If our observable is as shown below :

const observables = [
of(1,2,3,4).pipe(delay(500)),
from([10,11,12])
]

then output will be as follows
// [12,1]
// [12,2]
// [12,3]
// [12,4]

The console.log() output from the project function shows that the last emitted value from the first completed observable is used in all calculations. It is combined with each of the second observable values .Hence: if one observable emits values before the others do, then those values are lost.

5. concatMap: This operator maps each source value to an inner observable and concatenates the values from each inner observable sequentially. It waits for each inner observable to complete before moving on to the next one. Use concatMap over mergeMap when order is important for you.

Example:

import { of } from 'rxjs';
import { concatMap, delay } from 'rxjs/operators';

// Create an observable that emits three values
const sourceObservable = of(1, 2, 3);
// Use concatMap to concatenate the values from the inner observables
const resultObservable = sourceObservable.pipe(
concatMap((value) => {
// Create an inner observable that emits the value after a delay
return of(value).pipe(delay(1000));
})
);
// Subscribe to the result observable
resultObservable.subscribe((value) => {
console.log(value); // 1 2 3
});

In this example, `sourceObservable` emits three values: 1, 2, and 3. For each value emitted, `concatMap` creates an inner observable using `of` operator and emits the value after a delay of one second. It waits for each inner observable to complete before moving on to the next one. Therefore, the values from each inner observable will be emitted sequentially in the order they were mapped.

6. exhaustMap: The exhaustMap operator works by mapping each source value to an observable, and then subscribing to that observable. It ensures that only one inner observable is active at a time. If a new source value arrives while an inner observable is still active, the new value is ignored until the inner observable completes.

Here’s an example to demonstrate the usage of exhaustMap in Angular:

const $exhaustMap = from([1,2,3,4]).pipe(
exhaustMap(data=>{
return of(data).pipe(delay(500));
})
)

$exhaustMap.subscribe(data=> {
console.log('exhaustMap data', data); //1
})

Regarding what happens if any of the requests fail in `switchMap`, `mergeMap`, or `forkJoin`:

— switchMap: If any of the inner observables created by `switchMap` throws an error, the error will be propagated to the error callback of the `subscribe` method. Additionally, the subscription to the previous inner observable will be canceled, and `switchMap` will switch to the new inner observable.

— mergeMap: If any of the inner observables created by `mergeMap` throws an error, the error will be propagated to the error callback of the `subscribe` method. However, the error in one inner observable will not affect the other inner observables. `mergeMap` will continue to merge values from other inner observables.

-forkJoin: If any of the observables passed to `forkJoin` throws an error, the error will be propagated to the error callback of the `subscribe` method. In this case, `forkJoin` will not emit any result value. If you need to handle individual errors of each observable in `forkJoin`, you can use the `catchError` operator within each observable before passing them to `forkJoin`.

It’s important to note that error handling strategies and behavior may vary based on your specific use case and how you handle errors within your code.

46. What is dependency injection ?

In software enginering — dependency injection is the process of creating an instance (object) of a class A and providing this instance to class B so that the functionalities of class A can be use in class B.

In context of Angular — dependency injection is the process of creating an instance (object) of a Service and providing this instance to a component so that the functionalities of service can be use in the component. One of the ways to implement dependency injection is through the constructor method of the component.

47. What’s the difference between debounce and setTimeout ?

Debouncing is a technique used in JavaScript to limit the frequency of a function call that gets triggered repeatedly within a short period. It is often used in scenarios where an event (such as scrolling,resizing or api calls with search input change) can trigger frequent function calls, but you want to ensure that the function is only executed once after a certain delay when the event has stopped.

Code to implement ‘Debounce’ in Javascript:

HTML code:

<input type="text" onkeyup="search()">

JavaScript code:

let timerId;
let delay=1000;

function debounce(callback, delay) {
if(timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(()=>{
callback();
},delay)
}
function api() {
console.log('api call code here');
}
function search() {
debounce(api, delay);
}

setTimeout, on the other hand, is a built-in JavaScript function that schedules the execution of a function after a specified delay. It is commonly used for tasks that need to be performed after a certain period, such as animations, timeouts, or delayed operations.

Example of setTimeout:

Let’s consider a simple scenario where we want to display a notification after 2 seconds of a button click.

const showNotification = () => {
console.log('Notification: Button clicked!');
};

const button = document.getElementById('my-button');
button.addEventListener('click', () => {
setTimeout(showNotification, 2000);
});

In this example, the showNotification function will be executed after a delay of 2000 milliseconds (2 seconds) when the button is clicked.

48. What are RxJS key features ?

RxJS has several key features that make it a powerful tool for handling asynchronous data streams in JavaScript:

  1. Observables: RxJS is built around the concept of Observables, which represent asynchronous data streams. Observables can be transformed, combined, and consumed in a declarative way using operators.
  2. Operators: RxJS provides a wide range of operators that can be used to transform and manipulate Observables. These operators include `map`, `filter`, `reduce`, `scan`, `merge`, `concat`, `switchMap`, and many others.
  3. Error handling: RxJS provides operators for handling errors in Observables, such as `catchError` and `retry`.
  4. Schedulers: RxJS provides schedulers for controlling the timing and execution context of Observables. Schedulers can be used to control the concurrency of Observables, to delay or throttle emissions, and to run Observables on different threads or processes.
  5. Backpressure handling: RxJS provides backpressure handling mechanisms for dealing with Observables that produce data faster than it can be consumed. These mechanisms include `buffer`, `throttle`, `debounce`, and others.
  6. Interoperability: RxJS can be used with other libraries and frameworks, such as Angular, React, and Node.js. RxJS also supports integration with other reactive programming libraries and platforms, such as ReactiveX and RxJava.
  7. Testability: RxJS provides testing utilities for creating and manipulating Observables in unit tests. This makes it easier to test asynchronous code and ensure that Observables emit the expected values.

49. How do you handle errors in RxJS observables ?

RxJS provides several operators for handling errors in Observables. The two main operators for error handling are `catchError` and `retry`.

  1. catchError: The `catchError` operator is used to catch errors that may occur in an Observable and handle them in a graceful way. It takes a function as an argument that returns another Observable or throws an error. If the function returns an Observable, the source Observable will be replaced with the returned Observable. If the function throws an error, the error will be propagated to the subscriber.

Here is an example:

import { of } from 'rxjs';
import { catchError } from 'rxjs/operators';

of(1, 2, 3).pipe(
map(num => {
if (num === 2) {
throw new Error('Oops!');
}
return num;
}),
catchError(err => {
console.error(err.message);
return of(4, 5, 6);
})
).subscribe(
num => console.log(num),
err => console.error(err),
() => console.log('Complete')
);

In this example, the `map` operator throws an error when it encounters the number 2. The `catchError` operator catches the error and logs the error message to the console. It then replaces the source Observable with a new Observable that emits the numbers 4, 5, and 6. 2. retry: The `retry` operator is used to automatically retry an Observable when it encounters an error. It takes an optional argument that specifies the maximum number of retries.

Here is an example:

import { of } from 'rxjs';
import { map, retry } from 'rxjs/operators';

of(1, 2, 3).pipe(
map(num => {
if (num === 2) {
throw new Error('Oops!');
}
return num;
}),
retry(2)
).subscribe(
num => console.log(num),
err => console.error(err),
() => console.log('Complete')
);

In this example, the `map` operator throws an error when it encounters the number 2. The `retry` operator retries the Observable up to 2 times before propagating the error to the subscriber.

50. How do you implement backpressure in RxJS ?

Backpressure is a mechanism used in reactive programming to handle situations where an Observable is emitting data at a faster rate than it can be consumed. This can lead to issues such as high memory usage, slow processing, and even crashes. RxJS provides several operators for implementing backpressure, including `buffer`, `throttle`, `debounce`, `sample`, and `switchMap`.

  1. buffer: The `buffer` operator collects emitted values from the source Observable into an array and emits the array when it reaches a specified size. It can be used to temporarily store emitted values until they can be processed.

Here is an example:

import { interval } from 'rxjs';
import { bufferTime } from 'rxjs/operators';

interval(100).pipe(
bufferTime(1000)
).subscribe(
values => console.log(values),
err => console.error(err),
() => console.log('Complete')
);

In this example, the `interval` Observable emits a value every 100 milliseconds. The `bufferTime` operator collects the emitted values into an array and emits the array every 1000 milliseconds.

2. throttle: The `throttle` operator throttles the emissions of the source Observable by discarding emissions that occur within a specified time window. It can be used to limit the rate of emissions from the source Observable.

Here is an example:

import { interval } from 'rxjs';
import { throttleTime } from 'rxjs/operators';

interval(100).pipe(
throttleTime(1000)
).subscribe(
num => console.log(num),
err => console.error(err),
() => console.log('Complete')
);

In this example, the `interval` Observable emits a value every 100 milliseconds. The `throttleTime` operator discards emissions that occur within 1000 milliseconds of the previous emission.

3. debounce: The `debounce` operator delays emissions from the source Observable until a specified time has elapsed since the last emission. It can be used to filter out rapid emissions and emit only the last value.

Here is an example:

import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

fromEvent(document, 'keyup').pipe(
debounceTime(1000)
).subscribe(
event => console.log(event.target.value),
err => console.error(err),
() => console.log('Complete')
);

In this example, the `fromEvent` Observable emits a value every time a key is released on the document. The `debounceTime` operator delays emissions until 1000 milliseconds have elapsed since the last emission.

4. sample: The `sample` operator emits the most recent value from the source Observable at a specified time interval. It can be used to emit the most recent value at a regular interval, regardless of how many values are emitted.

Here is an example:

import { interval } from 'rxjs';
import { sampleTime } from 'rxjs/operators';

interval(100).pipe(
sampleTime(1000)
).subscribe(
num => console.log(num),
err => console.error(err),
() => console.log('Complete')
);

5. switchMap: The `switchMap` operator can be used to limit the number of concurrent emissions from the source Observable. Here’s an example of using `switchMap` to implement backpressure:

import { from, interval } from 'rxjs';
import { switchMap } from 'rxjs/operators';

// An Observable that emits a value every 100ms
const source$ = interval(100);
// An Observable that processes values
const processValue = value => {
return from(new Promise(resolve => {
// Simulate processing time
setTimeout(() => {
console.log(`Processed value: ${value}`);
resolve();
}, 1000);
}));
};
// Use switchMap to limit the number of concurrent emissions
const limitedSource$ = source$.pipe(
switchMap(value => processValue(value), 2) // Only allow 2 concurrent emissions
);
limitedSource$.subscribe(
value => console.log(`Received value: ${value}`),
err => console.error(err),
() => console.log('Complete')
);

In this example, the `source$` Observable emits a value every 100 milliseconds. The `processValue` function simulates processing time by returning a Promise that resolves after 1 second. The `switchMap` operator limits the number of concurrent emissions to 2, so only 2 values will be processed at a time. The `limitedSource$` Observable is subscribed to and emits the processed values.

Using `switchMap` in this way ensures that the processing of values is limited to a specific number at a time, preventing the system from being overwhelmed with too many values to process at once.

51. What is the purpose of operators in RxJS, and can you give an example of a common operator ?

Operators in RxJS are functions that can be used to transform, filter, or combine data emitted by observables. Operators are one of the key features of RxJS and allow developers to create complex data processing pipelines with ease.

One of the most common operators in RxJS is the `map` operator. The `map` operator is used to transform the emitted values from an observable by applying a function to each value.

Here’s an example:

import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const source$ = of(1, 2, 3);
const doubled$ = source$.pipe(
map(value => value * 2)
);

doubled$.subscribe(
value => console.log(value), // Output: 2, 4, 6
err => console.error(err),
() => console.log('Complete')
);

In this example, the `of` function is used to create an observable that emits the values 1, 2, and 3. The `map` operator is then used to double each value emitted by the observable. The `doubled$` observable is subscribed to and emits the transformed values, which are logged to the console.

The `map` operator is just one example of the many operators available in RxJS. Other common operators include `filter`, `reduce`, `scan`, `merge`, `concat`, and `switchMap` among others. These operators can be combined in various ways to create complex data processing pipelines that can handle real-world scenarios.

52. Can you explain what is the purpose of using schedulers in RxJS, and give an example of a common scheduler ?

In RxJS, a scheduler is an object that provides a way to control the timing of when events are emitted by observables. Schedulers can be used to schedule tasks to be executed at a specific time, delay the execution of tasks, or specify on which thread the tasks should be executed. The purpose of using schedulers is to provide developers with more fine-grained control over the timing and execution of observables.

One common scheduler in RxJS is the `observeOn()` operator. The `observeOn()` operator is used to specify the scheduler on which an observable should emit its values. Here’s an example:

import { from } from 'rxjs';
import { observeOn } from 'rxjs/operators';
import { asyncScheduler } from 'rxjs';
const source$ = from([1, 2, 3]);const async$ = source$.pipe(
observeOn(asyncScheduler) // Emit values on the async scheduler
);
async$.subscribe(
value => console.log(value), // Output: 1, 2, 3
err => console.error(err),
() => console.log('Complete')
);

In this example, the `from()` function is used to create an observable that emits the values 1, 2, and 3. The `observeOn()` operator is then used to specify that the observable should emit its values on the async scheduler, which will cause the values to be emitted asynchronously. The `asyncScheduler` is a common scheduler in RxJS that schedules tasks to be executed asynchronously using `setTimeout()`.

Schedulers can also be used to delay the execution of tasks, control the order in which tasks are executed, or specify on which thread the tasks should be executed. Some common schedulers in RxJS include `async`, `queue`, `animationFrame` and `immediate` among others.

53. What is the difference between a pipeable operator and a patch operator in RxJS ?

Pipeable operators are the recommended way to use operators in RxJS since version 5.5. Pipeable operators are imported as standalone functions and are then used in a pipeline by chaining them together with the `pipe()` function. Pipeable operators are pure functions that take an observable as their input and return a new observable as their output, allowing multiple operators to be composed together to form a pipeline.

Here’s an example of using pipeable operators to transform an observable:

import { of } from 'rxjs';
import { map, filter } from 'rxjs/operators';

const source$ = of(1, 2, 3, 4, 5);
const filtered$ = source$.pipe(
filter(value => value % 2 === 0),
map(value => value * 2)
);
filtered$.subscribe(
value => console.log(value), // Output: 4, 8
err => console.error(err),
() => console.log('Complete')
);

In this example, the `filter()` and `map()` operators are imported as standalone functions and then used in a pipeline with the `pipe()` function to create a new observable. The `filter()` operator is used to only allow even values to pass through, and the `map()` operator is used to double the remaining values.

Patch operators, on the other hand, were the original way to use operators in RxJS prior to version 5.5. Patch operators are imported as methods on the `Observable` class and are then used by calling them directly on an observable. Patch operators modify the behavior of the observable instance they are called on, and cannot be composed together in the same way as pipeable operators.

Here’s an example of using patch operators to transform an observable:

import { of } from 'rxjs';

const source$ = of(1, 2, 3, 4, 5);
const filtered$ = source$
.filter(value => value % 2 === 0)
.map(value => value * 2);

filtered$.subscribe(
value => console.log(value), // Output: 4, 8
err => console.error(err),
() => console.log('Complete')
);

In this example, the `filter()` and `map()` operators are called directly on the `source$` observable instance, which modifies its behavior to only allow even values to pass through and double the remaining values. Patch operators can still be used in RxJS, but pipeable operators are recommended for their increased composability and modularity.

54. What are services in Angular ?

In Angular, services are a crucial part of the architecture that allows you to share data, logic, and functionality across different components or throughout an application. Services are used to encapsulate and provide reusable functionality, such as data retrieval from a server, data manipulation, authentication, logging, and more. Here are some key aspects and characteristics of services in Angular:

  1. Singleton pattern: Angular services are typically implemented as singletons. This means that there is only one instance of a service throughout the application, and it can be shared by multiple components. When a service is injected into different components, they all receive the same instance, ensuring data consistency and efficient memory usage.
  2. Injectable decorator: To make a class act as an Angular service, it needs to be decorated with the `@Injectable` decorator. This decorator enables dependency injection and allows the service to be provided and injected into other Angular components.
  3. Dependency Injection (DI): Angular’s dependency injection system is used to provide instances of services to the components that require them. Components can declare dependencies on services by specifying them in their constructor parameters, and Angular’s DI system resolves and injects the appropriate service instances automatically.
  4. Business logic and data manipulation: Services are typically responsible for implementing business logic and performing data manipulation. For example, a service might handle HTTP requests to retrieve data from a server, perform data transformations, or interact with a database.
  5. Data sharing and communication: Services act as intermediaries for sharing data between components. They can store and manage shared data, allowing components to access and modify it. Services facilitate communication and coordination among components that may not have a direct parent-child relationship.
  6. Separation of concerns: Services help in separating business logic and data-related operations from the presentation layer (components and templates). This promotes code reusability, maintainability, and testability, as the logic can be decoupled from the UI and easily tested in isolation.
  7. Lifecycle and state management: Services can have their own lifecycle and maintain state. They can be initialized during application startup or lazy-loaded when needed. Services can also manage application-wide state, allowing components to interact with and update shared data.
  8. Testing: Services can be easily unit tested since they are separate from the UI components. By isolating and testing the services independently, you can verify the correctness of the business logic, data manipulation, and interactions with external systems or APIs.

Let’s consider an example to explain Angular services.

Suppose you are building a book management application where users can view and add books to their personal library. You want to implement a service called `BookService` that will handle the retrieval and management of book-related data.

First, you would create a new Angular service using the Angular CLI command:


ng generate service book

This will generate a `book.service.ts` file that contains the initial structure of the service.

In the `book.service.ts` file, you can define the `BookService` class and implement various methods and properties. Here’s an example implementation:


import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Book } from './book.model';

@Injectable({
providedIn: 'root'
})
export class BookService {
private apiUrl = 'https://api.example.com/books';

constructor(private http: HttpClient) {}

getAllBooks(): Observable {
return this.http.get(this.apiUrl);
}

addBook(book: Book): Observable {
return this.http.post(this.apiUrl, book);
}

deleteBook(bookId: number): Observable {
const url = `${this.apiUrl}/${bookId}`;
return this.http.delete(url);
}
}

In this example, the `BookService` is decorated with the `@Injectable` decorator, indicating that it can be injected into other Angular components. The `providedIn: ‘root’` option ensures that the service is available as a singleton throughout the application. The `BookService` has three methods:

  1. `getAllBooks()`: This method sends an HTTP GET request to the API endpoint (`this.apiUrl`) and retrieves a list of books as an array of `Book` objects.
  2. `addBook(book: Book)`: This method sends an HTTP POST request to the API endpoint, adding a new book to the database. It takes a `Book` object as a parameter and returns the added book.
  3. `deleteBook(bookId: number)`: This method sends an HTTP DELETE request to the API endpoint, deleting the book with the specified ID (`bookId`).

Other components in your application, such as `BookListComponent` or `BookAddComponent`, can then inject the `BookService` and use its methods to interact with book-related data.

For example, in the `BookListComponent`, you can inject the `BookService` and use the `getAllBooks()` method to fetch the list of books:


import { Component, OnInit } from '@angular/core';
import { Book } from './book.model';
import { BookService } from './book.service';

@Component({
selector: 'app-book-list',
templateUrl: './book-list.component.html',
styleUrls: ['./book-list.component.css']
})
export class BookListComponent implements OnInit {
books: Book[];

constructor(private bookService: BookService) {}

ngOnInit() {
this.bookService.getAllBooks().subscribe(books => {
this.books = books;
});
}
}

In this example, the `BookListComponent` injects the `BookService` through the constructor and uses the `getAllBooks()` method to retrieve the list of books asynchronously. The retrieved books are stored in the `books` property of the component, which can then be rendered in the template.

By using the `BookService` as a centralized data management service, you can maintain separation of concerns and easily share book-related data and operations across multiple components in your Angular application.

Services help to keep components lean by offloading complex logic and data operations, and enable efficient communication and data sharing between components.

55. What is the difference between AOT and JIT ?

For better Understanding it is first important to understand what is JIT which used to be default Angular compilation mode till Angular 8. After JIT , we will se how AOT works and how its different from JIT :

Just-in-Time (JIT)

In JIT compilation mode the TS code written by the developer is compiled to JS code during the build creation. Now, this compiled js code still contains some angular specific code ( for components, decorators, change detection, Dependency Injection etc.)which is compiled at the browser end again at runtime ,with the help of JIT compiler sent along with the build .

In JIT mode when Angular application is bootstrapped in the browser, the JIT compiler performs a lot of work to analyze the components in the application at runtime and generate code in memory. When the page is refreshed, all the work that has been done is thrown away, and the JIT compiler does the work all over again.

Ahead-of-Time (AOT)

The TS code written by the developer is compiled to JS code, this js has already been compiled for angular as well. Now, this compiled js code is compiled by the browser again so that the html can be rendered. But, the catch here is that the features of angular have already been taken care of by AOT compiler and hence the browser don’t have to worry much about component creation, change detection, Dependency Injection. So, we have :

Faster rendering

There’s no need to download the Angular compiler if the app is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload.

Detect template errors earlier

The AOT compiler detects and reports template binding errors during the build step before users can see them.

Better security

AOT compiles HTML templates and components into JavaScript files long before they are served to the client. With no templates to read and no risky client-side HTML or JavaScript evaluation, there are fewer opportunities for injection attacks.

You can also refer Angular’s official documentation link for understanding AOT here

56. What are the different building blocks of Angular ?

Angular consists of several building blocks that work together to create robust web applications. Here are the key building blocks of Angular:

  1. Components: Components are the fundamental building blocks of an Angular application. They encapsulate the application’s UI and logic, representing different parts of the user interface. Components consist of a template (HTML markup), styles (CSS), and a TypeScript class that defines the component’s behavior.
  2. Templates: Templates define the structure and layout of the UI for a component. They use HTML markup combined with Angular’s template syntax, which includes directives, data binding, and other features to manipulate and display data dynamically.
  3. Directives: Directives are instructions given to the HTML markup that modify its behavior or appearance. Angular provides built-in directives like `ngIf`, `ngFor`, and `ngSwitch` for conditional rendering, iteration, and switching logic. Additionally, Angular allows you to create custom directives to extend the functionality of your application.
  4. Services: Services provide a way to organize and share common functionality across multiple components. Services handle tasks such as data retrieval from APIs, data manipulation, authentication, logging, and more. They are typically injected into components or other services using dependency injection.
  5. Modules: Modules are containers that group related components, directives, services, and other code into cohesive units. Angular applications are composed of multiple modules, including the root module (`AppModule`) and feature modules. Modules help with organization, encapsulation, and manage dependencies within an application.
  6. Dependency Injection (DI): Dependency Injection is a design pattern and mechanism used in Angular to manage the dependencies of components and services. It allows you to inject dependencies into a class without explicitly creating or managing those dependencies yourself. Angular’s DI system provides a way to declare, provide, and inject dependencies through constructor parameters or property injection.
  7. Routing: Angular’s Router module allows you to implement client-side navigation and define routes for different components. It provides features like route configuration, parameter passing, route guards for authentication and authorization, lazy loading of modules, and more. Routing enables the creation of single-page applications (SPAs) with multiple views.
  8. Forms: Angular provides powerful form-handling capabilities, including both template-driven forms and reactive forms. Forms allow you to capture user input, perform validation, and handle form submission. Angular forms provide features like two-way data binding, form validation, form controls, form groups, and form builders.
  9. Pipes: Pipes are a way to transform and format data in templates. They allow you to apply filters, manipulate dates, format numbers, convert text case, and more. Angular provides built-in pipes like `date`, `uppercase`, `lowercase`, and `currency`, and you can create custom pipes for specific transformation needs.

These building blocks work together to create a structured and modular Angular application. Components define the UI, templates render the UI, services provide common functionality, modules organize the application, DI manages dependencies, routing enables navigation, forms handle user input, and pipes transform data for display. Understanding and effectively utilizing these building blocks is essential for developing Angular applications.

57. How do you use the retry() operator in RxJS, and what is its purpose ?

The `retry()` operator is used in RxJS to resubscribe to an observable if an error occurs. The operator will automatically resubscribe to the source observable, potentially with a delay or other customization options, and continue emitting values to its subscribers. The `retry()` operator can be useful in scenarios where the observable may fail due to intermittent network errors or other issues, allowing the application to recover from these errors and continue operating.

Here’s an example of how to use the `retry()` operator:

import { of } from 'rxjs';
import { map, mergeMap, retry } from 'rxjs/operators';

const source$ = of('http://my-api.com/data');
const data$ = source$.pipe(
mergeMap(url => fetch(url)), // Assume fetch() returns a promise with the data
map(response => response.json()),
retry(3) // Retry up to 3 times if an error occurs
);

data$.subscribe(
data => console.log(data),
err => console.error(err),
() => console.log('Complete')
);

In this example, the `source$` observable emits a single value — a URL that points to an API endpoint. The `mergeMap` operator is used to call the `fetch()` function with the URL and return a promise that resolves with the response data. The `map` operator is then used to parse the response data as JSON.

The `retry()` operator is used after the `map()` operator to specify that the observable should be retried up to 3 times if an error occurs. If an error occurs during the execution of the observable, RxJS will automatically resubscribe to the source observable up to 3 times, allowing the application to potentially recover from network errors.

It’s worth noting that the `retry()` operator can be customized with additional options, such as a delay between retries or a predicate function that determines which errors should trigger a retry. These options can be useful for handling more complex scenarios.

58. What is Angular change detection and how does it work ?

Angular’s change detection is a mechanism that detects and propagates changes in the application’s data model to update the corresponding views. It ensures that the UI reflects the current state of the data. When there are changes in the application’s data, Angular’s change detection system automatically updates the affected components and their child components. Here’s how Angular’s change detection works:

  1. Initialization: When a component is created, Angular initializes its change detector. The change detector tracks the component’s properties and listens for changes.
  2. Change detection tree: Angular constructs a tree-like structure known as the change detection tree, which represents the component hierarchy. Each component has its own change detector, and child components are nested within their parent’s change detector.
  3. Detecting changes: Angular performs change detection by running a change detection cycle. This cycle is triggered by various events, such as user interactions, timers, or asynchronous operations. By default, Angular automatically triggers change detection for the entire application after these events.
  4. Change detection cycle: During a change detection cycle, Angular starts from the root component’s change detector and traverses the change detection tree in a top-down manner.
  5. Checking for changes: In each component, Angular checks the properties that are bound to the component’s template. It compares the current value of each property with its previous value.
  6. Updating the view: If Angular detects a change in a component’s property, it updates the corresponding view to reflect the new value. This includes updating the DOM, re-rendering the component’s template, and triggering any necessary reflows.
  7. Child component check: After updating the current component, Angular continues the change detection cycle by moving to the child components within the change detection tree. It recursively performs change detection on each child component.
  8. Binding propagation: If changes occur in a parent component, Angular propagates these changes to its child components. This ensures that any affected child components are also updated accordingly.
  9. Immutable data: Angular’s change detection relies on object references to detect changes. If the reference to an object remains the same, Angular assumes that the object has not changed. Therefore, when working with immutable data patterns, it’s important to ensure that new objects are created to represent changes.
  10. Performance optimizations: Angular’s change detection system includes several performance optimizations. It skips unnecessary change detection cycles for components that have not been affected by changes. Angular also supports the OnPush change detection strategy, which allows components to specify that they should only be checked for changes when their input properties change.

By efficiently detecting and propagating changes, Angular’s change detection system helps keep the application’s UI in sync with the underlying data model, ensuring a responsive and up-to-date user experience.

59. What is zone js in Angular ?

Zone.js is a JavaScript library used in Angular to provide execution context and hooks into asynchronous operations. It allows Angular to track and manage the execution of asynchronous tasks, such as event handling, timers, promises, and XHR requests. Zone.js enables Angular to perform change detection and update the UI when asynchronous operations complete.

Here’s an example to illustrate the use of Zone.js in Angular:

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

@Component({
selector: 'app-example',
template: `
<button (click)="simulateAsyncTask()">Simulate Async Task</button>
<p>Status: {{ status }}</p>
`
})
export class ExampleComponent {
status: string = 'Not started';
simulateAsyncTask() {
this.status = 'Processing...';
setTimeout(() => {
// Simulating an asynchronous task completion
this.status = 'Completed';
}, 2000);
}
}

In this Angular component, we have a button and a paragraph displaying the status of an asynchronous task. When the button is clicked, the `simulateAsyncTask()` method is called. Inside the method, we update the `status` property to indicate that the task is being processed. Then, we use the `setTimeout` function to simulate a delay of 2 seconds.

Behind the scenes, Zone.js intercepts the `setTimeout` call and hooks into the asynchronous operation. It allows Angular to track the execution of the task and ensures that change detection is triggered when the task completes. When the timeout expires, the callback function is executed, and the `status` property is updated to indicate that the task is completed. As a result, the UI is automatically updated to reflect the new status.

Conclusion :

Zone.js provides Angular with a way to seamlessly integrate asynchronous operations into the change detection mechanism, enabling efficient updating of the UI when asynchronous tasks finish. It simplifies the handling of asynchronous code and ensures that Angular remains aware of changes happening within the asynchronous context.

60. How to dynamically create form fields with FormArray in Angular ?

To dynamically create form fields with `FormArray` in Angular, you can follow these steps:

  1. Import the necessary modules and services: — Import `FormBuilder` and `FormGroup` from `@angular/forms`.
  2. Create the form group and form array in the component: — In the component class, create a form group using the `FormBuilder` and define a form array within it.
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';

@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
})

export class DynamicFormComponent implements OnInit {
dynamicForm: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.dynamicForm = this.formBuilder.group({
formArrayName: this.formBuilder.array([]),
});
}
get formArray(): FormArray {
return this.dynamicForm.get('formArrayName') as FormArray;
}
// Other methods for adding, removing, and accessing form array controls
}

3. Implement methods to add and remove form array controls:

— Implement methods to add and remove form array controls within the component.

— These methods should use the `FormArray` methods `push()` and `removeAt()` to add or remove form array controls.

//...

addFormControl() {
const control = this.formBuilder.control('', Validators.required);
this.formArray.push(control);
}

removeFormControl(index: number) {
this.formArray.removeAt(index);
}
//...

4. Generate form fields dynamically in the template:

— In the component’s template, use `*ngFor` to iterate over the form array controls and generate the corresponding form fields dynamically.

<form [formgroup]="dynamicForm" (ngsubmit)="onSubmit()">
<div formarrayname="formArrayName">
<div *ngfor="let control of formArray.controls; let i = index">
<input [formcontrolname]="i" type="text">
<button (click)="removeFormControl(i)">Remove</button>
</div>
</div>
<button (click)="addFormControl()">Add Field</button>
<button type="submit">Submit</button>
</form>

In the example above, the `formArray` is accessed using the `formArrayName` property, and `*ngFor` is used to iterate over the form array controls. Each control is rendered as an input field, and a “Remove” button is provided to remove the corresponding control.

5. Handle form submission:

— Implement the logic to handle form submission in the component, using the `FormGroup` instance to access the form values and perform any necessary operations.

//...

onSubmit() {
if (this.dynamicForm.valid) {
const formValues = this.dynamicForm.value;
// Handle form submission
}
}
//...

By following these steps, you can dynamically create form fields using `FormArray` in Angular. The form array allows you to add or remove form controls dynamically, and the form values can be accessed and processed as needed.

61. What is ngZone in Angular ?

In Angular, `NgZone` is a service provided by the Angular framework that helps manage and control the execution of asynchronous tasks and change detection. It is responsible for triggering change detection and updating the view when changes occur.

The primary purpose of `NgZone` is to handle and optimize the execution of code that runs outside of Angular’s zone, such as events from third-party libraries or asynchronous operations like timers, AJAX requests, or WebSockets.

By default, Angular runs in a zone called the “Angular zone.” When code executes within this zone, Angular’s change detection mechanism is triggered automatically, and the view is updated accordingly. However, when code runs outside of the Angular zone, Angular may not be aware of the changes, leading to potential issues with the application state and view synchronization.

`NgZone` provides a way to explicitly run code inside or outside of the Angular zone. It offers two methods for executing code: `run()` and `runOutsideAngular()`.

1. run() : The `run()` method executes the provided function inside the Angular zone. This ensures that any changes triggered by the function will be detected and updated in the view.

import { Component, NgZone } from '@angular/core';

@Component({
selector: 'app-example',
template: `
<button (click)="onClick()">Run Code Inside NgZone</button>
`,
})

export class ExampleComponent {
constructor(private ngZone: NgZone) {}
onClick() {
this.ngZone.run(() => {
// Code executed inside NgZone
// Angular change detection is triggered
});
}
}

In the above example, the `onClick()` method is wrapped inside the `run()` method of `NgZone`. When the button is clicked, the code inside the `run()` function is executed within the Angular zone, ensuring that any changes made are detected and updated in the view.

2. runOutsideAngular() : The `runOutsideAngular()` method allows you to execute code outside of the Angular zone. This is useful for running code that doesn’t require Angular’s change detection or when optimizing performance for tasks that don’t affect the UI.

import { Component, NgZone } from '@angular/core';

@Component({
selector: 'app-example',
template: `
<button (click)="onClick()">Run Code Outside NgZone</button>
`,
})

export class ExampleComponent {
constructor(private ngZone: NgZone) {}
onClick() {
this.ngZone.runOutsideAngular(() => {
// Code executed outside NgZone
// Angular change detection is not triggered
});
}
}

In the above example, the `onClick()` method runs the code inside the `runOutsideAngular()` method. This ensures that the code is executed outside of the Angular zone, preventing unnecessary change detection and view updates.

Conclusion :

Using `NgZone`, you can control and optimize the execution of code inside and outside the Angular zone, ensuring efficient change detection and synchronization between the application state and the view.

62. Can event triggered in parent cause change detection in child with OnPush strategy in Angular ?

No, events triggered in the parent component cannot directly cause change detection in a child component with the `OnPush` change detection strategy in Angular. The `OnPush` strategy only triggers change detection in a component when one of the following conditions is met:

  1. The input properties of the component change.
  2. An event emitted by the component itself or one of its child components is received.

To demonstrate this, let’s consider an example with a parent component and a child component, both using the `OnPush` change detection strategy:

// parent.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-parent',
template: `
<button (click)="triggerEvent()">Trigger Event</button>
<app-child [inputproperty]="inputProperty"></app-child>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent {
inputProperty: string = 'Initial value';
triggerEvent() {
// Event triggered in the parent component
console.log('Event triggered in parent component');
}
}
// child.component.ts
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-child',
template: `
{{ inputProperty }}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
@Input() inputProperty: string;
}

In this example, the `ParentComponent` has a button that triggers the `triggerEvent()` method. However, since the `ParentComponent` and `ChildComponent` both use the `OnPush` change detection strategy, the event triggered in the parent component will not directly trigger change detection in the child component.

To propagate changes from the parent to the child component, you would need to update an input property of the child component. For example, you can modify the `triggerEvent()` method in the `ParentComponent` as follows:

triggerEvent() {
this.inputProperty = 'New value'; // Update input property of child component
}

By updating the input property value, Angular’s change detection mechanism will detect the change and trigger change detection within the child component with the `OnPush` strategy. This will update the child component’s view accordingly.

Conclusion :

To summarize, events triggered in the parent component do not directly cause change detection in a child component with the `OnPush` strategy. However, you can indirectly trigger change detection by updating an input property of the child component from the parent component.

Therefore, if an event is triggered in the parent component, it will not automatically trigger change detection in a child component with the `OnPush` strategy. This behavior is intentional to optimize performance by reducing unnecessary change detection cycles.

63. Can event triggered in child cause change detection in parent with OnPush strategy in Angular ?

No, an event triggered in a child component cannot directly cause change detection in the parent component with the `OnPush` change detection strategy in Angular. The `OnPush` strategy only triggers change detection in a component when one of its input properties changes or when an event emitted by the component itself or its child components is received.

However, you can propagate changes from the child component to the parent component using techniques like EventEmitter or a shared service. Here’s an example to illustrate how you can achieve this:

// child.component.ts
import { Component, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-child',
template: `
<button (click)="triggerEvent()">Trigger Event</button>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
@Output() childEvent: EventEmitter = new EventEmitter();
triggerEvent() {
this.childEvent.emit(); // Emit event from child component
}
}
// parent.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-parent',
template: `
<app-child (childevent)="handleChildEvent()"></app-child>
<p>Event Received: {{ eventReceived }}</p>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent {
eventReceived: boolean = false;
handleChildEvent() {
this.eventReceived = true; // Update state in parent component
}
}

In this example, the `ChildComponent` emits a custom event using the `childEvent` EventEmitter when the button is clicked. The `ParentComponent` listens to this event and triggers the `handleChildEvent()` method, which updates the `eventReceived` property in the parent component.

Conclusion:

By updating the state in the parent component, Angular’s change detection mechanism detects the change and triggers change detection in the parent component, which will update the view accordingly.

Please note that while the change detection in the parent component is triggered in response to the event emitted by the child component, it is not directly caused by the event itself. Instead, it is the change in the parent component’s state that triggers the change detection.

64. How to optimize an Angular application ?

Optimizing an Angular application involves various strategies and techniques to improve its performance and efficiency. Here are some steps you can take to optimize your Angular application:

  1. Minify and bundle your code: Use a build tool like Angular CLI(ng build — prod) to minify and bundle your application code. This reduces the file size and improves the load time of your application.
  2. Lazy loading modules: Split your application into smaller modules and lazy load them when needed. This approach reduces the initial bundle size and improves the initial load time of your application.
  3. Use Ahead-of-Time (AOT) compilation: Enable AOT compilation in your Angular application. AOT compiles your templates during the build process, resulting in faster rendering and improved performance.
  4. Optimize network requests: Reduce the number of HTTP requests by combining multiple requests into a single one using techniques like HTTP batching or using server-side rendering (SSR) to pre-render pages. Implement caching mechanisms to store and reuse frequently accessed data.
  5. Optimize rendering: Avoid unnecessary re-rendering of components by using the `OnPush` change detection strategy and leveraging the `ChangeDetectionRef` API when needed.
  6. Use Angular Universal: Consider implementing server-side rendering (SSR) using Angular Universal. SSR improves the initial rendering time and can enhance search engine optimization (SEO) by providing fully rendered pages to search engine crawlers.
  7. Optimize Angular performance tools: Leverage Angular performance tools Angular DevTools, and Lighthouse to identify performance bottlenecks, memory leaks, and other issues in your application. Use the performance profiling features to analyze and optimize your code.
  8. Tree shaking and dead code elimination: Ensure that you have configured your build process to perform tree shaking and dead code elimination. This eliminates unused code from your application, resulting in a smaller bundle size.
  9. Optimize CSS and images: Optimize your CSS by reducing the number of selectors, removing unused styles, and minifying the CSS files. Use image sprite which is a collection of images put into a single image. A web page with many images can take a long time to load and generates multiple server requests. Using image sprites will reduce the number of server requests and save bandwidth.

Conclusion :

Remember that optimization is an iterative process, and the specific optimizations required may vary depending on the nature of your application. Monitor your application’s performance and gather feedback from users to identify areas that need further optimization.

65. Explain pure and impure pipe in Angular ?

In Angular, pipes are used to transform data in templates. They can be categorized as pure pipes and impure pipes based on their behavior and performance characteristics.

  1. Pure Pipes: Pure pipes are the default type of pipes in Angular. They are designed to be pure functions that take an input value and return a transformed output value. Pure pipes are stateless and deterministic, meaning their output is solely dependent on their input, and they don’t have any side effects. Angular optimizes pure pipes by executing them only when their input values change.

Here’s an example of a pure pipe in Angular:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'testPipe',
pure: true
})
export class TestPipe implements PipeTransform {
transform(value: string): string {
Object.keys(value).forEach(function(key,index) {
// key: the name of the object key
// index: the ordinal position of the key within the object
value[key] = value[key].toUpperCase()
});
return value;
}
}

In the above example, the `TestPipe` is a pure pipe that transforms a string to uppercase. The `pure: true` setting in the `@Pipe` decorator indicates that this pipe is pure. It will only execute the `transform` function when the `value` input changes.

Suppose we have HTML code as following:-

{{ user | testPipe}} in HTML

and component code as following:-

user = { name:'test', city: 'test city'};

and the new changes are :-

this.user.city = "new test city"

For the above example, testPipe will not execute as object reference is not changed, To allow the pipe to execute , we have to make the pure attribute of testPipe as false or we need to make following changes in the component code:-

this.user = {
name: 'new test',
city: 'new test city'
}

In above code, testPipe will execute as object reference is changed.

2. Impure Pipes:

Impure pipes, on the other hand, are pipes that may have side effects and can be executed more frequently. They are explicitly marked as impure by setting the `pure` property to `false` in the `@Pipe` decorator. Impure pipes are not optimized by Angular for change detection and can be executed multiple times, even when the input values haven’t changed.

Here’s an example of an impure pipe in Angular:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'testPipe',
pure: false
})
export class TestPipe implements PipeTransform {
transform(value: string): string {
Object.keys(value).forEach(function(key,index) {
// key: the name of the object key
// index: the ordinal position of the key within the object
value[key] = value[key].toUpperCase()
});
return value;
}
}

Suppose we have HTML code as following:-

{{ user | testPipe }} in HTML

and component code as following:-

user = { name:'test', city: 'test city'};

and the new changes are :-

this.user.city = "new test city"

For the above example, testPipe will execute, as Impure pipes executes every time angular detects any changes regardless of the change in the input value.

Conclusion:

It’s important to note that while pure pipes are the default and recommended type in Angular due to their performance optimizations, impure pipes can still be useful in certain scenarios when dealing with stateful or non-deterministic transformations. However, using impure pipes excessively or inappropriately can impact the performance of your Angular application.

66. Explain unit testing in Angular ?

Unit testing in Angular involves testing individual components, services, and other units of code in isolation to ensure they work correctly. Angular provides the TestBed and various testing utilities to facilitate unit testing. Here’s an example to demonstrate unit testing in Angular:

Let’s consider a simple component called `CalculatorComponent` that performs basic arithmetic operations:


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

@Component({
selector: 'app-calculator',
template: `
<div>
<input type="number" [(ngmodel)]="num1">
<input type="number" [(ngmodel)]="num2">
<button (click)="add()">Add</button>
<p>Result: {{ result }}</p>
</div>
`
})
export class CalculatorComponent {
num1: number;
num2: number;
result: number;

add() {
this.result = this.num1 + this.num2;
}
}

To write unit tests for this component, we can utilize the testing framework provided by Angular. Here’s an example test using the Jasmine testing framework:


import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CalculatorComponent } from './calculator.component';

describe('CalculatorComponent', () => {
let component: CalculatorComponent;
let fixture: ComponentFixture;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ CalculatorComponent ]
}).compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(CalculatorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should add two numbers', () => {
component.num1 = 5;
component.num2 = 10;
component.add();
expect(component.result).toBe(15);
});
});

In the test above, we use the `describe` function to define a test suite for the `CalculatorComponent`. Inside the `beforeEach` function, we create an instance of the component using `TestBed.createComponent` and assign it to `fixture`. We then assign the component instance to `component` for easy access within the tests.

The `it` function defines an individual test case. In this case, we set `num1` and `num2` to 5 and 10, respectively, call the `add` method, and expect the `result` to be 15.

To run the unit tests, you can use Angular’s CLI command `ng test`, which executes the tests using Karma test runner.

Conclusion :

By writing unit tests, you can ensure that individual components, services, and other units of code behave as expected, helping you catch bugs early and maintain code quality in your Angular application.

67. How to test an Angular Service ?

To test an Angular service, you can use Angular’s testing utilities and techniques. Here’s an example that demonstrates how to test an Angular service:

Let’s assume you have a simple service called `UserService` that performs user-related operations:

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

@Injectable()
export class UserService {

private users: string[] = [];

addUser(user: string) {
this.users.push(user);
}

getUserCount() {
return this.users.length;
}

deleteUser(user: string) {
const index = this.users.indexOf(user);
if (index !== -1) {
this.users.splice(index, 1);
}
}
}

Now, let’s write a unit test for the `UserService` using Angular’s testing utilities:

import { TestBed } from '@angular/core/testing';
import { UserService } from './user.service';

describe('UserService', () => {
let service: UserService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UserService);
});

it('should add a user', () => {
service.addUser('John');
expect(service.getUserCount()).toBe(1);
});

it('should delete a user', () => {
service.addUser('John');
service.addUser('Jane');
service.deleteUser('John');
expect(service.getUserCount()).toBe(1);
});
});

In the test above, we use the `describe``TestBed.configureTestingModule()`, and then inject the `UserService` using `TestBed.inject()` and assign it to the `service` variable.

The `it` function defines individual test cases. In the first test, we call the `addUser` method with the user ‘John’ and expect the user count to be 1. In the second test, we add two users, ‘John’ and ‘Jane’, then call the `deleteUser` method with ‘John’ and expect the user count to be 1.

To run the unit tests for the service, you can use the Angular CLI command `ng test`, which executes the tests using Karma test runner.

Conclusion :

By writing tests for your Angular services, you can ensure that the service functions as expected, including its methods and data manipulations. It helps you catch errors, verify the behavior, and maintain the correctness of your service logic.

68. Explain ngAfterContentInit hooks ?

The `ngAfterContentInit` hook is a lifecycle hook in Angular that is called after Angular initializes the content projected into a component. This hook is useful when you want to perform some initialization or setup logic after the content has been projected into the component.

Here’s an example of how you can use the `ngAfterContentInit` hook in an Angular component:

import { Component, AfterContentInit, ContentChild } from '@angular/core';

@Component({
selector: 'app-my-component',
template: `
<ng-content></ng-content>
`
})
export class MyComponent implements AfterContentInit {
@ContentChild('myContent') myContent: ElementRef;

ngAfterContentInit() {
// This code will run after the content has been projected into the component
console.log('Content initialized:', this.myContent.nativeElement.textContent);
}
}

n this example, the `MyComponent` component has a template that includes the `<ng-content></ng-content>` tag. This tag is a placeholder where the content will be projected when the component is used.

Inside the component class, we use the `@ContentChild` decorator to get a reference to the projected content. In this case, we’re looking for an element with the template reference variable `myContent`. You can use other selectors, such as CSS classes or component types, depending on your specific use case.

The `ngAfterContentInit` method is implemented as part of the `AfterContentInit` interface, which allows us to hook into the lifecycle of the component. Inside this method, you can perform any necessary initialization or logic based on the projected content. In this example, we log the text content of the projected element to the console.

When you use the `MyComponent` component in another template and provide content to be projected, the `ngAfterContentInit` method will be called after the content has been initialized.

<app-my-component>
<div #mycontent>This content will be projected</div>
</app-my-component>

When the above code runs, the `ngAfterContentInit` method in `MyComponent` will be triggered, and it will log the text content of the projected `<div>` element to the console.

Remember to include the necessary imports for `Component`, `AfterContentInit`, and `ContentChild` from the `@angular/core` module in your Angular component.

69. Explain ngAfterViewInit hook with example ?

The `ngAfterViewInit` hook is a lifecycle hook in Angular that is called after Angular initializes the component’s view and its child views. This hook is useful when you need to perform some logic or operations that require access to the component’s view or its child views.

Here’s an example of how you can use the `ngAfterViewInit` hook in an Angular component:

import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';

@Component({
selector: 'app-my-component',
template: `
<div #myDiv>Some content</div>
`
})
export class MyComponent implements AfterViewInit {
@ViewChild('myDiv') myDiv: ElementRef;

ngAfterViewInit() {
// This code will run after the component's view has been initialized
console.log('View initialized:', this.myDiv.nativeElement.textContent);
}
}

In this example, the `MyComponent` component has a template that includes a `<div>l` element with the template reference variable `myDiv`. We use the `@ViewChild`decorator to get a reference to this element in the component class.

The `ngAfterViewInit` method is implemented as part of the `AfterViewInit` interface, which allows us to hook into the lifecycle of the component’s view. Inside this method, you can access and manipulate the DOM elements of the component’s view. In this example, we log the text content of the `

` element to the console. When the component’s view is initialized, Angular calls the `ngAfterViewInit` method, and you can perform any necessary operations that require access to the component’s view or its child views.

Here’s an example of using the `MyComponent` component in another template:

<app-my-component></app-my-component>

When the above code runs, the `ngAfterViewInit` method in `MyComponent` will be triggered, and it will log the text content of the `<div>` element to the console.

Remember to include the necessary imports for `Component`, `AfterViewInit`, `ViewChild`, and `ElementRef` from the `@angular/core` module in your Angular component.

Conclusion:

Note: It’s important to use the `ngAfterViewInit` hook with caution, as accessing and manipulating the DOM directly can go against the principles of Angular’s declarative approach. Whenever possible, it’s recommended to use Angular’s data binding and component interaction mechanisms instead of manipulating the DOM directly.

70. Difference between ngAfterContentInit and ngAfterViewInit ?

The `ngAfterContentInit` and `ngAfterViewInit` hooks are both lifecycle hooks in Angular, but they are used in different contexts and serve different purposes.

`ngAfterContentInit` is a lifecycle hook that is called after Angular initializes the content projected into a component. It is used when you need to perform initialization or setup logic that depends on the content projected into the component. This hook is typically used in components that have `<ng-content></ng-content>` tags in their templates to project content from the parent component. You can access the projected content using the `@ContentChild` decorator.

On the other hand, `ngAfterViewInit` is a lifecycle hook that is called after Angular initializes the component’s view and its child views. It is used when you need to perform logic or operations that require access to the component’s view or its child views. This hook is often used for DOM manipulation, accessing ViewChild elements, or interacting with third-party libraries that require the view to be fully rendered. You can access the view elements using the `@ViewChild` decorator.

Here’s a summary of the key differences between `ngAfterContentInit` and `ngAfterViewInit`:

  1. Purpose:

— `ngAfterContentInit`: Used for initialization or setup logic dependent on projected content.

— `ngAfterViewInit`: Used for logic or operations that require access to the component’s view or child views.

2. Timing:

— `ngAfterContentInit`: Called after content projection is initialized.

— `ngAfterViewInit`: Called after the component’s view and child views are initialized.

3. Decorators:

— `ngAfterContentInit`: Use `@ContentChild` decorator to access projected content.

— `ngAfterViewInit`: Use `@ViewChild` decorator to access view elements.

4. Usage:

— `ngAfterContentInit`: Typically used in components that project content from parent components.

— `ngAfterViewInit`: Typically used for DOM manipulation, accessing view elements, or interacting with third-party libraries.

Conclusion:

In summary, `ngAfterContentInit` is used when you want to perform initialization based on projected content, while `ngAfterViewInit` is used when you need to perform logic or operations that require access to the component’s view or child views.

71. What is View Encapsulation in Angular ?

In Angular, ViewEncapsulation is a feature that controls the way styles are applied and scoped to components. It is a mechanism that encapsulates the styles defined in a component to prevent them from affecting other components in the application.

By default, Angular uses the ViewEncapsulation.Emulated mode, also known as the “shadow DOM” emulation. In this mode, Angular emulates the behavior of the shadow DOM by adding a unique attribute to the component’s HTML elements and applying styles with these attributes. This way, styles defined in a component only affect the elements within that component’s template and do not leak out to other parts of the application.

There are three ViewEncapsulation modes available in Angular:

  1. ViewEncapsulation.Emulated (default): This mode emulates the shadow DOM by adding unique attributes to the component’s elements. The styles defined within the component’s template are scoped to that component only. ViewEncapsulation.Emulated will add the css style in the head section of your website and reference your component’s unique id(_ngcontent) to apply it.
  2. ViewEncapsulation.None: In this mode, styles defined in a component’s template are not encapsulated and can affect the entire application. It’s important to use this mode with caution, as it can lead to style collisions and unintended side effects when multiple components use the same styles.
  3. ViewEncapsulation.ShadowDom: This mode uses the native browser’s shadow DOM implementation to encapsulate the styles. It requires the browser to support the shadow DOM. With this mode, the component’s styles are truly isolated within the component and do not leak out to other components or the global styles. ViewEncapsulation.ShadowDom will add the css style inside the generated DOM of your component.

To specify the ViewEncapsulation mode for a component, you can use the `encapsulation` property in the component’s metadata:

import { Component, ViewEncapsulation } from '@angular/core';

@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css'],
encapsulation: ViewEncapsulation.Emulated // or ViewEncapsulation.None or ViewEncapsulation.ShadowDom
})
export class MyComponent {
// Component logic goes here
}

Conclusion:

By understanding and utilizing ViewEncapsulation in Angular, you can have better control over styles and prevent unintended style interference between components in your application.

72. What is the use of polyfills ?

Polyfills are additional scripts that provide compatibility for features or APIs that are not supported by all browsers. These scripts are automatically included in an Angular application during the build process to ensure that the application can run on a wide range of browsers, including older versions.

Here’s an example to illustrate the usage of polyfills in an Angular application:

  1. Open the “polyfills.ts” file: In your Angular project, locate the “polyfills.ts” file, which is usually located in the “src” folder. This file contains the configuration for the polyfills.
  2. Uncomment or add the required polyfills: Inside the “polyfills.ts” file, you’ll find a section with a list of polyfills that can be uncommented or added as needed. Each polyfill corresponds to a specific feature or API that may not be supported by all browsers.

For example, if you need to support older browsers that lack support for certain JavaScript features, you can uncomment or add the polyfill for the specific feature. Let’s say you want to provide support for the `Array.from` method, which might not be available in all browsers. You can uncomment or add the following line:

// Uncomment below to enable support for 'Array.from' in older browsers
// import 'core-js/es/array/from';

This line imports the polyfill from the “core-js” library to ensure that the `Array.from` method works in browsers that don’t support it natively.

Similarly, you can uncomment or add other polyfills based on the features or APIs you need to support.

3. Build and deploy the application: After configuring the required polyfills in the “polyfills.ts” file, you can proceed to build and deploy your Angular application as usual using the Angular CLI or your preferred build process.

During the build process, Angular will bundle the application along with the specified polyfills. These polyfills will be automatically loaded in the browser alongside your application code.

Conclusion:

By including the appropriate polyfills, your Angular application can leverage modern features and APIs while maintaining compatibility with a wider range of browsers, including older versions. The polyfills ensure that the application behaves consistently across different browsers, providing a smooth and functional user experience.

Remember to review and update your polyfills periodically to ensure compatibility with evolving browser standards and to optimize the performance of your application.

73. What is scan operator in RxJS ?

In RxJS (Reactive Extensions for JavaScript), the scan operator is used to perform an accumulation operation on the values emitted by an observable sequence. It resembles the Array.prototype.reduce() function in JavaScript but operates on an observable stream of values instead of an array.

The scan operator takes an accumulator function and an optional seed value as its parameters. The accumulator function is called for each value emitted by the source observable, and it accumulates the intermediate result based on the previous accumulated value and the current value from the source. The accumulated value is then emitted to the resulting observable sequence.

Here’s the general syntax of the scan operator:

const $scanOperator = from([1,2,3,4]).pipe(
scan((sum,num) => sum+num)
);

$scanOperator.subscribe(data=> {
console.log('scan operator data', data);
});
// output :
// scan operator data 1
// scan operator data 3
// scan operator data 6
// scan operator data 10

Note: In scan operator, intermediate result is emitted while in reduce operator intermediate result is not emitted and only the final result is emitted.

Conclusion :

The scan operator is useful for scenarios where you need to maintain state or accumulate values over time, such as tracking the total count, calculating averages, or simulating a running total.

74. How does spyOn work in Angular ?

In Angular, `spyOn` is a utility provided by the Jasmine testing framework, which is used to create test spies. Spies allow you to observe and control the behavior of functions during testing. They are commonly used to replace certain function implementations with custom ones, track function calls, and assert on their behavior.

Here’s an example to demonstrate how `spyOn` works in Angular:

Let’s assume you have a service called `DataService` that interacts with an external API:

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

@Injectable()
export class DataService {
fetchData(): Promise {
return new Promise((resolve) => {
// Simulating an asynchronous API call
setTimeout(() => {
const data = 'Some data from API';
resolve(data);
}, 1000);
});
}
}

Now, let’s write a unit test for the `DataService` using `spyOn` to mock the API call:

import { TestBed } from '@angular/core/testing';
import { DataService } from './data.service';

describe('DataService', () => {
let service: DataService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(DataService);
});
it('should fetch data from the API', () => {
const apiResponse = 'Mocked API response';
spyOn(service, 'fetchData').and.returnValue(Promise.resolve(apiResponse));
service.fetchData().then((data) => {
expect(data).toBe(apiResponse);
expect(service.fetchData).toHaveBeenCalled();
});
});
});

In the test above, we use the `spyOn` function to create a spy on the `fetchData` method of the `DataService`. The `and.returnValue` method is used to specify the return value of the spy, which is a resolved promise with the mocked API response.

Then, we call the `fetchData` method and assert that the returned data matches the mocked API response using the `expect` function. Additionally, we use the `toHaveBeenCalled` matcher to verify that the `fetchData` method was called.

By using `spyOn`, we can replace the original implementation of the `fetchData` method with a mock implementation and control its behavior during testing. This allows us to isolate the service and focus on testing its interactions without making actual API calls.

Remember to import the necessary testing utilities (`TestBed`, `spyOn`, etc.) from the appropriate packages (`@angular/core/testing`, `jasmine`, etc.) in your test files.

Note: It’s important to mention that `spyOn` is not specific to Angular but is part of the Jasmine testing framework, which is commonly used in Angular unit testing.

75. How to mock http request in Angular ?

To mock HTTP requests in Angular unit tests, you can use the `HttpClientTestingModule` and `HttpTestingController` provided by Angular’s testing utilities.

Here’s an example to demonstrate how to mock an HTTP request in Angular:

Let’s assume you have a service called `DataService` that makes HTTP requests using Angular’s `HttpClient`:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class DataService {
constructor(private http: HttpClient) {}
fetchData(): Promise<string> {
return this.http.get<string>('https://api.example.com/data').toPromise();
}
}

Now, let’s write a unit test for the `DataService` and mock the HTTP request:

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { DataService } from './data.service';

describe('DataService', () => {
let service: DataService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [DataService]
});
service = TestBed.inject(DataService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify();
});

it('should fetch data from the API', () => {
const mockResponse = 'Mocked API response';
service.fetchData().then((data) => {
expect(data).toBe(mockResponse);
});
const req = httpMock.expectOne('https://api.example.com/data');
expect(req.request.method).toBe('GET');
req.flush(mockResponse);
});
});

In the test above, we import `HttpClientTestingModule` and use it in the `TestBed.configureTestingModule()` to configure the testing module. We also inject the `HttpTestingController` to interact with the HTTP requests.

Inside the test, we call the `fetchData` method of the `DataService` and assert on the response data. Then, we use `httpMock.expectOne()` to intercept the HTTP request and return a mock response using `req.flush()`. Finally, we use `httpMock.verify()` in the `afterEach` block to ensure that no unexpected requests were made.

Conclusion :

By using the `HttpClientTestingModule` and `HttpTestingController`, we can mock the HTTP requests and control their responses, allowing us to test the behavior of the service without making actual API calls. Note: Make sure to import the necessary testing utilities (`TestBed`, `HttpClientTestingModule`, `HttpTestingController`, etc.) from the appropriate packages (`@angular/core/testing`, `@angular/common/http/testing`, etc.) in your test files.

76. What is the difference between ‘from’ and ‘of’ operator in RxJS ?

In RxJS, the `from` and `of` operators are used to create observables from different types of data sources. Although they may seem similar, there is a fundamental difference between them:

  1. `from`: The `from` operator is used to create an observable from an array-like, iterable, or promise-based data source. It emits each item of the source one by one.
  
import { from } from 'rxjs';

const arraySource = from([1, 2, 3, 4, 5]);
// Emits: 1, 2, 3, 4, 5

const stringSource = from('Hello');
// Emits: 'H', 'e', 'l', 'l', 'o'

const promiseSource = from(fetch('https://api.example.com/data'));
// Emits the resolved value of the promise

The `from` operator is suitable when you have a collection of items, such as an array or iterable, and you want to emit each item sequentially.

2. `of`: The `of` operator is used to create an observable that emits a sequence of values. It emits all the provided values immediately.


import { of } from 'rxjs';

const source = of(1, 2, 3, 4, 5);
// Emits: 1, 2, 3, 4, 5

The `of` operator is useful when you want to create an observable that emits multiple values immediately, without the need for any asynchronous operations or iteration.

Conclusion :

In summary, the main difference between `from` and `of` lies in the type of data sources they can handle and the way they emit values. `from` is used for array-like, iterable, or promise-based data sources, emitting values one by one. `of` is used to emit a sequence of values immediately.

77. What is reduce operator in RxJS ?

In RxJS, the reduce operator is used to apply an accumulation function to the values emitted by an observable sequence and emit a single accumulated result. It is similar to the Array.prototype.reduce() function in JavaScript.

The reduce operator takes an accumulator function and an optional seed value as its parameters. The accumulator function is called for each value emitted by the source observable, and it accumulates the intermediate result based on the previous accumulated value and the current value from the source. The accumulated value is then emitted as the final result when the source observable completes.

Here’s the general syntax of the reduce operator:

const $reduceOperator = from([1,2,3,4]).pipe(
reduce((sum,num) => {
return sum+num;
})
);

$reduceOperator.subscribe(data=> {
console.log('reduce operator data', data);
})
// output
// reduce operator data 10

Note: In reduce operator, intermediate result is not emitted and only the final result is emitted, while in scan operator intermediate result is emitted.

Conclusion:

The reduce operator is useful when you want to obtain a single accumulated result from a sequence of values. It is commonly used for calculations that produce a final output, such as summing values, finding the maximum or minimum, or performing any other reduction operation on the emitted values.

78. What is the use of trackBy in Angular ?

In Angular, the `trackBy` function is used in conjunction with the `ngFor` directive to improve performance when rendering lists of items. By providing a `trackBy` function, Angular can track and update individual items in the list instead of re-rendering the entire list whenever a change occurs.

The `trackBy` function takes two arguments: the index of the item in the list and the item itself. It should return a unique identifier for each item. Angular uses this identifier to track the items and determine whether they have changed or moved within the list.

Here’s an example of how to use `trackBy` in an `ngFor` loop:

<!-- my-component.component.html -->
<ul>
<li *ngfor="let item of items; trackBy: trackByFn">{{ item.name }}</li>
</ul>
// my-component.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
];

trackByFn(index: number, item: any): number {
return item.id; // Unique identifier for each item
}
}

In this example, the `trackByFn` function returns the `id` property of each item as the unique identifier. Angular uses this identifier to track the items and update the DOM efficiently when changes occur.

By using `trackBy`, Angular avoids re-rendering and updating the entire list when an item is added, removed, or moved. Instead, it only updates the specific item that has changed, resulting in better performance and a smoother user experience, especially when dealing with large lists.

Note:

It’s important to note that the unique identifier returned by the `trackBy` function must remain stable for each item. If the identifier changes when an item is updated, Angular will treat it as a new item and re-render it. Therefore, it’s recommended to use an identifier that doesn’t change over the item’s lifetime, such as a unique ID from your data source.

--

--

Pravin M

I am a frontend developer with 10+ years of experience