Angular - sakib03/Interview GitHub Wiki
Angular Interview Questions & Answers
ANGULAR EVOLUTION – VERSION 1 TO VERSION 9 | VERSION UPDATES
The Missing Introduction to Angular and Modern Design Patterns
An intro to Observables and how they are different from promises
RxJS: (Angular folks - Few operator to know !)
How to use mergeMap and forkJoin to handle multiple API requests in Angular
How To Use ForkJoin — Angular Example
Angular Reactive Templates with ngIf and the Async Pipe
Top 10 ways to use Interceptors in Angular
Add multiple HTTP Interceptors to Angular Application
HTTP - Intercept requests and responses
Angular and DevExtreme -- Getting Started
Angular architecture is defined in main three layers is Core layer, Abstraction layer, and Presentation layer. This is also called High-Level Architecture.
Presentation Layer — This layer is mainly responsible for the design and user interface. Here we are defining all our angular components. It is displaying all templates and handling user events. Presentation layer also responsible for Unidirectional data flow (It means we have parents and children concept for components).
Abstraction layer — The abstraction layer decouples the presentation layer from the core layer. This layer will behave as a mediator and the facade for the presentation layer. It means that it will expose an API and coordinate the communication between presentation layer components and the core of the application. For example, here we call services to have data communication between template and core layer.
Core layer — This layer is the innermost layer of an application, though all outside communication happens here. In this layer, one can place all state management, core modules, and services. The core layer is responsible for encapsulating the state and behavior of an application. In angular, we have services to write all API calls which contain @Injectable to inject APIs to communicate with outside. All services lie in the core layer. In this layer, we could also place any validators, mappers, or more advanced use-cases that require manipulating many slices of our UI state.
A sequence of event that arrive asynchronously over time. It is an http response that arrives asynchronously. We have to convert the data into an array, then the data is provide only to the component that subscribe to this array
Parent to Child Component
Use @Input() decorator in child and use the same property name using property binding syntax. Bind the property name in html inside child component tag of parent component then pass the same property name in child using @Input
Child to Parent Component
Child to Parent is event communication, we need to assign eventEmitter class to the variable that use to create custom event and use @output to that variable in child component and emit event from child then pass that variable in the parent html by calling a function with $event parameter and create that function in parent
@VIEWCHILD : ViewChild allows a parent component to access a child component's content. This is handy when we want to call a child component's function or reference its properties.
We should use it inside ngAfterViewInit.
Used for DOM manipulation and passing data from child to parent.
When you are using @Input(), for every change the ngOnChanges() will be called which may causes more noise. Using ViewChild() Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated. So ViewChild() will not create such noise and is the prefer way over @Input().
Interceptor is used between api calls and angular. It is inject using @Injectable in the class in which we implements HttpInterceptor, in which it provides a intercept method which receives request as parameter and passes the request to the processing pipeline.
By intercepting the HTTP request, we can modify or change the value of the request.
- package.json file locates in project root and contains information about your web application. The main purpose of the file comes from its name package, so it'll contain the information about npm packages installed for the project.
- angular.json file locates at the root level of an Angular workspace provides workspace-wide and project-specific configuration defaults for build and development tools provided by the Angular CLI. Path values given in the configuration are relative to the root workspace folder.
ng lint run the linting tool on angular app code. It checks the code quality of angular project specified. It uses TSLint as default linting tool and uses the default configuration available in tslint.json fileLinting is the process of running a program that analyses your code for programmatic and stylistic errors. A Linting tool, or a linter, checks any potential errors in your code such as syntax errors, incorrectly spelled variable names, and many more. This can save time and help you write better code.
Form controls are the classes that hold the data values and the validations for every form elements.
Form group aggregates the value of each form control. If one elements validation is invalid whole form group will be invalid.
patchValue() method will also set Formcontrol values from a model but only for those which we have mentioned in the model. So, it is not necessary to pass all the model info in patchValue() method.
Structure of module.ts file:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
LoginComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
],
providers: [AuthenticationService],
bootstrap: [AppComponent]
Exports:[exports modules in case of custom modules]
Creating shared modules allows you to organize and streamline your code. You can put commonly used directives, pipes, and components into one module and then import just that module wherever you need it in other parts of your application.
Shared modules is used to share the components between modules. We will use
exports: [
SharedComponent
]
to export the component and then will import the modules which export this component into main module.
Directives can extend, change, modify the behavior of the DOM elements.
There are three types of directives:
Components, Structural and Attribute directives.
Subject is a special type of Observable in RxJs Library in which we can send our data to other components or services. A Subject is like an Observable but can multicast to many observers which means subject is at the same time an Observable and an Observer.
Here are some important points of subjects:
- A Subject is a Special type of Observable that allows value to be multicasted to many Observers.
- Subject are like event emitters.
- No Initial Value.
-
subject = new Subject();
Behavior Subject is similar to subject but only difference is that we can set the initial value .
A variant of subject that requires initial value.
const subject = new BehaviorSubject(0); // 0 is the initial value.
The HttpClient is an Angular module that allows your application to communicate with backend services over the HTTP protocol. You can perform all HTTP requests including GET, POST, PUT, PATCH and DELETE.
In Angular, when we are using the HttpClient module to communicate with a backend service and fetch some data, after fetching the data, we can broadcast it to multiple subscribers, all in one execution. This task of responding with data to multiple subscribers is called multicasting. It is specifically useful when we have multiple parts of our applications waiting for some data. To use multicasting, we need to use an RxJS subject. As observables are unicast, they do not allow multiple subscribers. However, subjects do allow multiple subscribers and are multicast.
AuthGuard is used to protect the routes from unauthorized access in angular. Auth guard provide lifecycle event called canActivate. The canActivate is like a constructor. It will be called before accessing the routes. The canActivate has to return true to access the page. If it returns false, we can not access the page. Read more
Auth-guard makes use of CanActivate interface and it checks for if the user is logged in or not. If it returns true, then the execution for the requested route will continue, and if it returns false, that the requested route will be kicked off and the default route will be shown.
ProtectRoutes:
As we learned about guarding routes with CanActivate, we can also protect child routes with the CanActivateChild guard. The CanActivateChild guard works similarly to the CanActivate guard, but the difference is its run before each child route is activated. We protected our admin feature module from unauthorized access, but we could also protect child routes within our feature module.
Lazy loading is the feature of angular which only loads the required javascript modules when a specific route is activated. We can create custom lazy loading modules for lazy loading component.
To lazy load Angular modules, use loadChildren (instead of component ) in your AppRoutingModule routes configuration as follows.
const routes: Routes = [ { path: 'items', loadChildren: () => import('./items/items.
npm install -g @angular/cli
ng new apm-new --prefix pm
In Angular, a component's styles can be encapsulated within the component's host element so that they don't affect the rest of the application. Read more
Pipes are a useful feature in Angular. They are a simple way to transform values in an Angular template. There are some built in pipes, but you can also build your own pipes. A pipe takes in a value or values and then returns a value.
Stackblitz Example:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'pipeFilter',
pure: false
})
export class FilterPipe implements PipeTransform {
transform(data: Array<Map<string, string>>, filters: Array<Ifilter>): Array<Map<string, string>> {
let filteredData = Array<Map<string, string>>();
for (let row of data) {
let exclude: boolean = false;
for (let filter of filters) {
if (filter.filter != '' && row.get(filter.header).indexOf(filter.filter) == -1) {
exclude = true;
break;
}
}
if (!exclude)
filteredData.push(row);
}
return filteredData;
}
}
Notes:
Pipe can be created by the @Pipe Decorator and it has metadata such as name: string, pure: true/false.
Pipe implements PipeTransform
By default, pipes are pure. A pure pipe is only called when Angular detects a change in the value or the parameters passed to a pipe. An impure pipe is called for every change detection cycle no matter whether the value or parameter(s) changes. Read more
RouterModule register the router service provider, declare the router directives such as router-outlet & routerLink and exposes the configured routes.
RouterModule knows about the configured routes, is by passing .forRoot() method in imports of @NgModule... like RouterModule.forRoot([])
If we are using routing in the application, as router routes the component we won't need a selector because selector is defined to nest a component. Routing Implementation:
1) Configure routes:
Define element in head tag <base href="/">
Add RouterModule to @NgModule imports array
Add each route to the forRoot array, each route definition requires a path & component, example [{path: '...', component:'...', redirectTo: '...', pathMatch: 'full/prefix'}]
- Routing Order Matters (top to bottom)
- Router 'path' value should not have no leading slash
- '' empty path for default route
- '**' two asterisk for wildcard route (if no routes matches)
2) Tie routes to action:
Add 'routerLink' attribute to any clickable element to, like <button [routerLink]="['/...']"></button>
First element in routerLink array is a path and all other elements are route parameters.
And, instead of routing from template using routerLink, we can route through code as well by using "this.router.navigate(['/...'])", here 'router' is an instance of Router class from '@angular/router'.
Then, to get a ActivatedRoute in routed page we can use "this.route.snapshot.paramMap.get('id')", here 'route' is an instance of ActivatedRoute class from '@angular/router'.
3) Place the view:
<router-outlet></router-outlet>
4) Route Parameter:
Example in RouterModule [{path: '.../:id'}] & in routerLink <button [routerLink]="['/...', object.id]"></button>
Reference Link: https://www.pluralsight.com/guides/forroot-and-forchild-static-methods-on-the-angular-router
Services are basically used for making data or logic accessible across the components.
- Can create an instance of a Service class and use it. Not recommended, because instance is local to the component so can't share data to other resources and can be problem to mock the service while testing.
- Register a Service with Angular, then Angular creates a single instance for the Service class called SingleTon. Specifically, Angular provides a built-in Injector, register a Service to an Injector and Injector then creates and manages the instance or a SingleTon. Then, if our Component needs a Service, it defines a Service in a Component class(constructor) as a dependency, then Angular Injector provides or injects a Service class instance when Component class instantiated, this process is called 'Dependency Injection'.
Dependency Injection: A coding pattern in which a class receives the instance of objects it needs (called dependencies) from and external source (Angular Injector) rather than creating themself.
RxJS is a library for composing data (asynchronous data) using observables sequences (stream), and transforming that data using an operators.
Observable is a collection of item over time. Unlike an array it doesn't retain and items, however emitted items can be observed over time.
Observables do nothing until we 'subscribe' it. When we subscribe, Observable start begin emitting notifications, there are 3 types of notifications:
- next: Next item is emitted
- error: An error occurred and no more items are emitted
- complete: No more items are emitted
Observable can stop by 'unsubscribe'
Observable are lazy so when we 'subscribe' it's get started, Subscribe method take an optional argument which is an 'observer' object, as name suggest observer object observes the stream and response to 3 types on notification, next,error,complete as mentioned above. We can define the handler function in an observer object to handle the notifications.
Scenario:
Request: When we call an HTTP GET method it returns an Observable, which will emit notifications, then we Subscribe to start the Observable and the GET request is sent, code continues along...
Response: When we have a response from the server, the Observable emits a 'next' notification and we process the emitted response. Note: When we request a HTTP GET the Observable emits the entire response as one emitted item, for example a single array of objects.
Observable Pipe: Pipe can be used to transform the each emitted item by using Observable operators.
Example:-
Service.ts
import { HttpClient, HttpErrorResponse } from "@angular/common";
import { Injectable } from "@angular/core";
import { Observable, throwError } from "rxjs";
import { catchError, tap } from "rxjs/operators";
import { IProduct } from "./product";
@Injectable({
providedIn: 'root'
})
export class ProductService {
private productUrl = 'URL';
constructor(private: http: HttpClient) { }
getProducts(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(this.productUrl).pipe(
tap(data => console.log('All: ', JSON.Stringify(data))),
catchError(this.handleError)
);
}
private handleError(err: HttpErrorResponse){
// Error handling code goes here...
}
}
Component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { IProduct } from "./product";
import { ProductService } from "./product.service";
import { Subscribtion } from "rxjs";
@Component({
selector: 'pm-products',
templateUrl: './product-list.component.html',
styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit, OnDestroy {
products: IProduct[] = [];
errorMessage: string = '';
// In TypeScript we can't declare a variable without assigning a default value, so below variable should be like...
// sub: Subscribtion | undefined;
sub!: Subscribtion; // or else we can assign like this, which tells TypeScript compiler that will assign value sometime later...
// known as definite assignment assertion...
// To prevent null or undefined errors in template use "safe navigation operator (?)", example {{ product?.id }}
constructor(private: productService: ProductService) { }
ngOnInit(): void {
this.sub = this.productService.getProducts().subscribe({
next: products => this.products = products,
error: err => this.errorMessage = err
});
}
ngOnDestroy(): void {
this.sub.unsubscribe();
}
}
Reference Link: https://medium.com/javascript-everyday/javascript-theory-promise-vs-observable-d3087bc1239a