Angular Interview Questions for Freshers

author image Hirely
at 09 Jan, 2025

Question: How do you handle HTTP requests in Angular?

Answer:

In Angular, HTTP requests are handled using the HttpClient module, which is part of Angular’s @angular/common/http package. The HttpClient provides a simplified API for making HTTP requests such as GET, POST, PUT, DELETE, etc., and returns Observables that you can subscribe to for handling the asynchronous data.

Handling HTTP requests in Angular involves the following steps:

  1. Importing the HttpClientModule.
  2. Using the HttpClient service to send HTTP requests.
  3. Subscribing to Observables to handle the asynchronous responses or errors.

Step 1: Import the HttpClientModule:

First, you need to import the HttpClientModule in your application’s root module (app.module.ts) so that Angular can inject the HttpClient service into your components and services.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';  // Import HttpClientModule

import { AppComponent } from './app.component';

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

Step 2: Inject the HttpClient Service:

Next, inject the HttpClient service into your component or service to make HTTP requests. The HttpClient has methods like get(), post(), put(), delete(), and patch() to make different types of requests.

Example of a GET Request:

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

@Injectable({
  providedIn: 'root'
})
export class DataService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/posts';  // Example API

  constructor(private http: HttpClient) { }

  // GET Request using HttpClient
  getPosts(): Observable<any> {
    return this.http.get<any>(this.apiUrl);  // Makes a GET request
  }
}

In this example:

  • getPosts() is a method that makes an HTTP GET request to retrieve data from an API.
  • The return type of http.get() is an Observable, which will emit the response data when the request completes.

Example of a POST Request:

To send data to the server (for example, creating a new post), use the post() method of HttpClient.

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

@Injectable({
  providedIn: 'root'
})
export class DataService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/posts';  // Example API

  constructor(private http: HttpClient) { }

  // POST Request using HttpClient
  createPost(postData: any): Observable<any> {
    return this.http.post<any>(this.apiUrl, postData);  // Sends data to API
  }
}

In this example:

  • createPost() sends a POST request with the postData object to the server.
  • The response will be emitted through the Observable.

Step 3: Subscribing to the Observable:

After you make an HTTP request, you subscribe to the returned Observable in order to get the actual data or handle errors.

Example: Subscribing in a Component:

import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-root',
  template: `
    <h1>Angular HTTP Example</h1>
    <div *ngFor="let post of posts">
      <p>{{ post.title }}</p>
    </div>
  `
})
export class AppComponent implements OnInit {
  posts: any[] = [];

  constructor(private dataService: DataService) { }

  ngOnInit() {
    // Subscribe to the Observable returned by getPosts() method
    this.dataService.getPosts().subscribe(
      (response) => {
        this.posts = response;  // Handle the response and assign it to the posts array
      },
      (error) => {
        console.error('Error occurred:', error);  // Handle error
      }
    );
  }
}

In this component:

  • The ngOnInit() lifecycle hook subscribes to the Observable returned by the getPosts() method from DataService.
  • The data (response) is assigned to the posts array, which is then displayed in the template.

Handling Errors:

You can handle errors in HTTP requests using the catchError operator from RxJS. It’s important to handle errors to prevent your application from crashing if something goes wrong with the HTTP request.

Example: Handling Errors:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/posts';

  constructor(private http: HttpClient) { }

  // Handling errors with catchError
  getPosts(): Observable<any> {
    return this.http.get<any>(this.apiUrl).pipe(
      catchError(error => {
        console.error('Error occurred:', error);
        return of([]);  // Return a fallback value (empty array) in case of error
      })
    );
  }
}

In this example:

  • The catchError operator intercepts any errors that occur during the HTTP request.
  • It logs the error and returns a fallback value (of([])), which prevents the Observable from failing and allows the application to continue running.

Configuring HTTP Headers and Parameters:

Sometimes you need to include headers, query parameters, or authentication tokens with your HTTP requests.

Example: Custom Headers:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/posts';

  constructor(private http: HttpClient) { }

  // GET Request with custom headers
  getPostsWithHeaders(): Observable<any> {
    const headers = new HttpHeaders({
      'Authorization': 'Bearer your-token',
      'Custom-Header': 'Header-Value'
    });
    
    return this.http.get<any>(this.apiUrl, { headers });
  }
}

In this example:

  • HttpHeaders is used to set custom headers for the HTTP request, such as an Authorization token.
  • The headers are passed as an option to the http.get() method.

Example: Query Parameters:

import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/posts';

  constructor(private http: HttpClient) { }

  // GET Request with query parameters
  getPostsWithParams(page: number, limit: number): Observable<any> {
    const params = new HttpParams().set('page', page.toString()).set('limit', limit.toString());

    return this.http.get<any>(this.apiUrl, { params });
  }
}

In this example:

  • HttpParams is used to build query parameters for the HTTP request.
  • The params are passed as an option to the http.get() method to send them along with the request.

Conclusion:

To handle HTTP requests in Angular:

  1. Import the HttpClientModule into your application.
  2. Inject HttpClient into your service or component to make requests.
  3. Use get(), post(), put(), delete(), etc., methods to interact with APIs.
  4. Subscribe to the returned Observable to handle responses and errors.
  5. Use RxJS operators like catchError, map, and others to manage data and errors effectively.

This approach provides a reactive, declarative way of handling HTTP requests, making Angular applications both scalable and maintainable.

Question: What are Angular pipes? Can you explain how they are used?

Answer:

In Angular, pipes are a powerful feature used to transform data in templates. They allow you to apply transformations to data before it is displayed to the user, such as formatting dates, filtering lists, or transforming text. Pipes take the input data and return a transformed value to be rendered in the view.

Key Points about Angular Pipes:

  1. Pipes are simple functions: A pipe is essentially a function that takes an input value, applies a transformation, and returns the transformed value.
  2. Built-in pipes: Angular provides a set of built-in pipes, such as DatePipe, CurrencyPipe, UpperCasePipe, LowerCasePipe, and more.
  3. Custom pipes: You can also create custom pipes to implement specific transformations for your application.
  4. Pure and Impure pipes: By default, Angular pipes are pure, meaning they only update when the input value changes. However, pipes can be made impure if they depend on something other than input values (e.g., external data or state).

Using Built-in Pipes:

1. Common Built-in Pipes:

  • date: Formats a date according to the specified format.
  • currency: Formats a number as currency.
  • uppercase and lowercase: Transforms text to uppercase or lowercase.
  • json: Converts an object into a JSON-formatted string.
  • slice: Slices a string or array.
  • async: Resolves an asynchronous value (like an Observable or Promise).

Examples of Using Built-in Pipes:

<!-- Format a date -->
<p>{{ today | date:'short' }}</p>

<!-- Format a number as currency -->
<p>{{ amount | currency:'USD' }}</p>

<!-- Convert text to uppercase -->
<p>{{ text | uppercase }}</p>

<!-- Convert text to lowercase -->
<p>{{ text | lowercase }}</p>

<!-- Slice an array or string -->
<p>{{ ['apple', 'banana', 'cherry'] | slice:1:3 }}</p>

<!-- JSON representation of an object -->
<p>{{ person | json }}</p>

Explanation of the Above Examples:

  • date: today | date:'short' transforms a Date object into a human-readable date format (e.g., “1/24/2024, 10:25 AM”).
  • currency: amount | currency:'USD' converts the numeric amount into a currency format, with $ symbol for USD.
  • uppercase: text | uppercase converts the text to uppercase letters.
  • lowercase: text | lowercase converts the text to lowercase letters.
  • slice: ['apple', 'banana', 'cherry'] | slice:1:3 returns a subarray from index 1 to index 3, resulting in ['banana', 'cherry'].
  • json: person | json converts an object into a JSON string representation.

Creating Custom Pipes:

While Angular provides many built-in pipes, you can create your own custom pipes for more specific transformations.

Steps to Create a Custom Pipe:

  1. Create a Pipe class using the @Pipe decorator.
  2. Implement the transform() method, which will contain the logic for transforming the input data.
  3. Register the custom pipe in an Angular module.

Example: Creating a Custom Pipe

Let’s create a custom pipe that capitalizes the first letter of each word in a string.

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

@Pipe({
  name: 'capitalize'  // Custom name of the pipe
})
export class CapitalizePipe implements PipeTransform {
  transform(value: string): string {
    if (!value) return value;  // Return if value is empty or null
    return value.replace(/\b\w/g, (char) => char.toUpperCase());
  }
}

Using the Custom Pipe in the Template:

After creating the custom pipe, you can use it just like any built-in pipe in your template:

<p>{{ 'hello world' | capitalize }}</p>

The output will be:

Hello World

Pure vs Impure Pipes:

  • Pure pipes: These pipes only update when their input value changes (default behavior). Angular optimizes pure pipes for performance, ensuring they are recalculated only when necessary.

  • Impure pipes: These pipes are recalculated every time Angular checks for changes, regardless of whether the input value has changed. Impure pipes are typically used when the data to be transformed comes from an external source or is updated frequently (e.g., time-dependent data or user-triggered updates).

How to Create an Impure Pipe:

You can make a pipe impure by setting the pure property to false in the @Pipe decorator:

@Pipe({
  name: 'impurePipe',
  pure: false  // Makes the pipe impure
})
export class ImpurePipe implements PipeTransform {
  transform(value: any): any {
    // Custom transformation logic
    return value;
  }
}

Performance Considerations:

  • Pure Pipes: These are more performance-friendly because Angular only executes them when the input data changes.
  • Impure Pipes: These are less performant because they run more frequently, regardless of whether the input has changed.

For most use cases, it’s recommended to stick with pure pipes, unless you have a specific use case that requires an impure pipe (e.g., handling frequent data changes that are not bound to Angular’s change detection).


Summary of Angular Pipes Usage:

  • Purpose: Pipes transform data in templates for better presentation (e.g., formatting dates, filtering lists).
  • Built-in pipes: Angular provides several useful built-in pipes like date, currency, uppercase, and json.
  • Custom pipes: You can create your own pipes by implementing the PipeTransform interface and using the @Pipe decorator.
  • Pure vs impure pipes: By default, pipes are pure, meaning they only update when input changes. Impure pipes recalculate on every change detection cycle.

Pipes in Angular are a great way to apply reusable, declarative transformations to data in the UI layer, keeping components and templates clean and maintainable.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as Angular interview questions, Angular interview experiences, and details about various Angular job positions. Click here to check it out.

Related Posts

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now