Sunday, 24 August 2025

Frontend Interview Preparation - Q&A

Q1. How can you define a selector that only works for a screen for more than 700px?

You can use **CSS media queries**:

css
@media screen and (min-width: 700px) {
  selector {
    /* styles */
  }
}


This ensures styles only apply when the screen width is more than 700px. Useful for responsive design.

Q2. What is difference between let, const and var

-In JavaScript, let, const, and var are all used to declare variables, but they differ in scope, reassignment rules, and hoisting behavior

1. var

  • Scope: Function-scoped (or global if declared outside a function) — not block-scoped.
  • Reassignment: Can be reassigned and redeclared.
  • Hoisting: Hoisted to the top of the scope, initialized with undefined.
  • Use today: Rarely used now because it can cause bugs due to lack of block scope.

function testVar() {
    if (true) {
        var x = 10;
    }
    console.log(x); // 10 ✅ (var ignores block scope)
}


2. let

  • Scope: Block-scoped ({}), meaning it’s only accessible inside the block where it’s declared.
  • Reassignment: Can be reassigned but not redeclared in the same scope.
  • Hoisting: Hoisted but not initialized — accessing it before declaration causes a ReferenceError (Temporal Dead Zone).
  • Use: For variables whose values may change.

function testLet() { if (true) { let y = 20; } console.log(y); // ❌ ReferenceError }

3. const

  • Scope: Block-scoped.
  • Reassignment: Cannot be reassigned.
  • Hoisting: Same as let — hoisted but not initialized (Temporal Dead Zone).
  • Use: For variables whose values should not change (constants).
  • Note: For objects/arrays, the reference can’t change, but the contents can be modified.

const z = [1, 2, 3]; z.push(4); // ✅ Allowed (array contents can change) z = [5, 6]; // ❌ TypeError (reference change not allowed)


Q. What is hoisting?

Hoisting in JavaScript means that variable and function declarations are moved to the top of their scope (global or function) during the compilation phase, before the code is executed.

But there’s a catch — only declarations are hoisted, not initializations.

1️⃣ Hoisting with var

  • var is hoisted and initialized with undefined.
  • That’s why you can use a var variable before its declaration without getting an error (though it’s bad practice).

console.log(a); // undefined ✅ var a = 10; // Declaration is hoisted, initialization happens later

2️⃣ Hoisting with let and const

  • These are hoisted but not initialized.
  • They stay in the Temporal Dead Zone (TDZ) from the start of the scope until their declaration line.
  • Accessing them before declaration throws a ReferenceError.

console.log(b); // ❌ ReferenceError let b = 20;

3️⃣ Hoisting with Functions

  • Function declarations are fully hoisted — both their name and body.
  • You can call them before their definition.

sayHello(); // ✅ Works function sayHello() { console.log("Hello!"); }
  • Function expressions (assigned to var, let, const) behave like variables — only the variable declaration is hoisted, not the function value.

sayHi(); // ❌ TypeError: sayHi is not a function var sayHi = function() { console.log("Hi!"); };


Q3. How could you add an element to the end and beginning of the array?

- Add at end: `arr.push(element)`
- Add at beginning: `arr.unshift(element)`

Example:

let arr = [2,3];
arr.push(4); // [2,3,4]
arr.unshift(1); // [1,2,3,4]

Q4. How to validate a type of a variable in JS?

Use `typeof` operator:

typeof 123; // 'number'
typeof 'abc'; // 'string'
typeof true; // 'boolean'


Q5. Few examples of typeof in TypeScript?

TypeScript enhances `typeof` for type queries.

let msg = "Hello";
let len: typeof msg; // string

function fn(x: number) { return x; }
let y: ReturnType<typeof fn>; // number

Q6. How to define a parameter as an Option?

In TypeScript, mark it as optional using `?`:

function greet(name?: string) {
  console.log(name ? `Hello, ${name}` : "Hello");
}


Q7. How to define the constant inside of a class?

Use `static readonly`:

class MyClass {
  static readonly PI = 3.14;
}
console.log(MyClass.PI);


Q8. Few examples of main building blocks in Angular

- **Modules**: Organize code.
- **Components**: UI building blocks.
- **Templates**: HTML with Angular syntax.
- **Services**: Business logic.
- **Directives**: Modify DOM behavior.
- **Dependency Injection**: Provides services.

Q9. What is the difference between @Input and @Output, and where should they be used?

- @Input: Pass data **from parent to child**.
- @Output: Send events/data **from child to parent**.

Example:

// child.component.ts
@Input() title: string;
@Output() clicked = new EventEmitter<string>();

Q10. Promises Vs Observables

- **Promise**: Single value, eager, no cancellation.
- **Observable**: Multiple values over time, lazy, supports cancellation.

Example: Use Promise for one-time HTTP call, Observable for streaming data (like WebSockets).

Q11. Whats @ViewChild

Decorator to access child components, directives, or DOM elements directly.

@ViewChild('inputRef') input: ElementRef;
ngAfterViewInit() { this.input.nativeElement.focus(); }

Q12. What is HostListener

@HostListener listens to events on the host element.


@Directive({selector: '[hoverHighlight]'})
class HoverDirective {
  @HostListener('mouseenter') onEnter() { ... }
}

Q13. Subject Vs BehaviourSubject

- **Subject**: Emits values only to subscribers after subscription.
- **BehaviorSubject**: Stores last value and immediately sends it to new subscribers.

Use BehaviorSubject when you want subscribers to always have the latest state.

Q14. JS synchronous or async?

JS is **single-threaded synchronous** but uses **event loop** for async operations.
- Synchronous: Code runs line by line.
- Asynchronous: `setTimeout`, Promises handled via event loop.

Q15. Lifecycle hooks in Angular

- ngOnInit: Init logic.
- ngOnChanges: When @Input changes.
- ngAfterViewInit: After view init.
- ngOnDestroy: Cleanup.


Helps manage component lifecycle.

Q16. console.log(1=='1') and console.log(1==='1')

- '==': true (because it coerces types).
- '===`': false (strict comparison).

Q17. So (4 == '5') will be false?

Yes, because type coercion converts `'5'` to number, and `4 != 5`. So result is **false**.

Q18. Anonymous functions

Functions without a name. Often used in callbacks.

setTimeout(function(){ console.log('Hi'); }, 1000);

Q19. Calling Nested function func()()

If a function returns another function, you can call it immediately:

function outer() {
  return function inner() { console.log('Hi'); }
}
outer()(); // Hi

Q20. Engine Execution: setTimeout and console.log

`console.log` executes first (synchronous).
`setTimeout` goes to Web API, then callback queue, then event loop executes it **after main stack is empty**.

Q21. Global Context in JS

The default execution context: In browsers it's the **window object**, in Node.js it's **global**.

Q22. GET and POST Security aspects

- **GET**: Params visible in URL (less secure).
- **POST**: Params in body (more secure).

Never send password in GET; risk of logging, bookmarking, caching.

Q23. Real time example where you can use ViewChilds

Example: Auto-focusing an input field after loading a component.

@ViewChild('searchBox') search: ElementRef;
ngAfterViewInit(){ this.search.nativeElement.focus(); }


Q24. Parent/Child Component with @Input and @Output

Parent passes data to child via `@Input`, child emits events to parent via `@Output`.


// parent.html
<child [title]="parentTitle" (notify)="onNotify($event)"></child>


This enables component communication.

Q26. How to expose REST web services to frontend in Spring

🔹 1. Create a REST Controller in Spring Boot

In Spring, you expose REST endpoints using @RestController and @RequestMapping (or @GetMapping, @PostMapping, etc.).

import org.springframework.web.bind.annotation.*;
import java.util.*;

@RestController
@RequestMapping("/api/users")

public class UserController {

    // Example GET API
    @GetMapping
    public List<String> getAllUsers() {
        return Arrays.asList("Aamir", "John", "Maria");
    }

    // Example POST API
   @PostMapping
    public String createUser(@RequestBody String userName) {
        return "User " + userName + " created successfully!";
    }
}

👉 This exposes endpoints:

  • GET http://localhost:8080/api/users
  • POST http://localhost:8080/api/users

🔹 2. CORS (Cross-Origin Resource Sharing)

Frontend (Angular/React) usually runs on a different port (e.g., Angular: http://localhost:4200).
To allow frontend calls, enable CORS:

Option A: At Controller Level

@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "http://localhost:4200")  // Allow Angular app

public class UserController {
    // ...
}

Option B: Global Configuration

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

 @Configuration
public class WebConfig {

    
@Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {

            
@Override     
            
public void addCorsMappings(CorsRegistry registry) {
           registry.addMapping("/api/**")
                        .allowedOrigins("http://localhost:4200")
                        .allowedMethods("GET", "POST", "PUT", "DELETE");
            }
        };
    }
}


🔹 3. Consume API from Frontend

Angular Example (using HttpClient)

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

 @Injectable({
 providedIn: 'root'
})

export class UserService {
  private apiUrl = 'http://localhost:8080/api/users';

  constructor(private http: HttpClient) {}

  getUsers(): Observable<string[]> {
   return this.http.get<string[]>(this.apiUrl);
  }

   addUser(userName: string): Observable<string> {
   return this.http.post<string>(this.apiUrl, userName);
  }
}


🔹 4. Security Aspect

  • If using Spring Security, you need to configure allowed endpoints for frontend.
  • Example (permit /api/** without auth):

http.csrf().disable()
  .authorizeRequests()
    .antMatchers("/api/**").permitAll()
    .anyRequest().authenticated();


 Summary (Interview Answer):
To expose REST web services to frontend in Spring Boot:

  1. Create endpoints using @RestController.
  2. Handle cross-origin requests with @CrossOrigin or WebMvcConfigurer.
  3. Frontend calls these endpoints using HTTP clients (e.g., Angular HttpClient, React fetch).
  4. If Spring Security is enabled, configure access rules for APIs.

Q27. URL Shortening using TinyURL

You generate a unique key for a long URL and store mapping in DB. When user hits tiny URL, backend redirects to original.

Can use hashing + base62 encoding.

Q28. AuthGuard & Interceptor in Angular

- **AuthGuard**: Protects routes (checks if user logged in).
- **Interceptor**: Intercepts HTTP requests, adds JWT, handles errors.

Together they ensure security in Angular apps.

 

Mock Interview Preparation - Microservices in Spring Boot

I: Can you explain how you implemented microservices in your last project?

C: Sure. In my last project, I worked on a Digital Locker / Document Vault System where we followed a microservices architecture. 
We had separate services like User Service, Document Service, and Notification Service. 
- Each service had its own database to ensure loose coupling. 
- Services communicated using REST APIs for synchronous calls and Kafka for asynchronous, event-driven scenarios. 
- We used Spring Boot + Spring Cloud for building microservices, Eureka for service discovery, and Spring Cloud Gateway as the API Gateway. 
- Security was handled via OAuth2 with JWT tokens. 
- For deployment, we containerised each service with Docker and deployed them on Kubernetes (OpenShift). 
- To handle resilience, we used Resilience4j (circuit breakers, retries, fallbacks). 
This architecture gave us scalability, independent deployments, and fault isolation. 


🔁 Follow-ups

I: Why did you choose microservices instead of a monolith? 
C: In a monolith, even a small change requires redeploying the whole application. Scaling was also harder since everything scaled together. With microservices, we gained independent deployments, better scalability, fault isolation, and tech flexibility. 

I: Why Kafka when REST APIs were already there? 
C: REST works fine for synchronous calls, but for event-driven features like sending notifications after a document upload, Kafka allows asynchronous communication. If the notification Service was down, messages stayed in Kafka and were processed later. 

I: How did you manage databases across services? 
C: Each service had its own database. This ensured loose coupling and autonomy. For example, User Service used PostgreSQL and Document Service used MongoDB. If we used a single DB, services would get tightly coupled. 

I: How did you secure inter-service communication? 
C: We used OAuth2 with JWT tokens. Auth Service generated JWTs after login. Each request carried the JWT, and microservices validated it. This ensured stateless, centralised authentication. 

I: What challenges did you face? 
C: 
- Distributed logging → solved with ELK stack. 
- Service failures → handled with Resilience4j circuit breakers & retries. 
- Database consistency → used the saga pattern for long transactions. 
- Network latency from multiple calls → optimised with caching + async messaging. 

I: Why Eureka and API Gateway? 

C: 
- Eureka (Service Discovery): avoided hardcoding URLs, services registered dynamically. 
- API Gateway: acted as a single entry point, managed routing, authentication, and rate limiting. 

I: How did you deploy and manage microservices? 
C: Each service had its own Jenkins pipeline. We used Docker for containerization and deployed on Kubernetes (OpenShift). This gave us scalability, rolling updates, and independent deployments. 


Angular Interview Questions

What is a Memory Leak?

A memory leak happens when your app keeps holding onto memory that it no longer needs.
In Angular, this usually means you’ve created references (like event listeners, subscriptions, DOM objects) that are never cleaned up — so the Garbage Collector cannot free them.
Over time, the app’s memory usage keeps growing → leading to slow performance or even crashes.

Common Causes of Memory Leaks in Angular:

1. Unsubscribed Observables / Subscriptions

If you don’t unsubscribe in ngOnDestroy, the subscription stays alive.

2. Event Listeners not removed

If not removed, the component will still respond to resize even after destruction.

3. Timers not cleared

If you don’t clearInterval, it keeps running.

How to Prevent Memory Leaks

1. Unsubscribe properly

2. Use async pipe

Instead of subscribing manually:
3. Remove event listeners & clear timers

A memory leak in Angular means resources are not released properly (like Observables, event listeners, timers, or DOM references). The fix is to unsubscribe, clean up, and use Angular features (async pipe, takeUntil, ngOnDestroy`) properly.


How to copy a reference from one variable to another?


What is server-side rendering in Angular?

Server-Side Rendering (SSR) in Angular is the process of rendering Angular applications on the server instead of the browser. With SSR, the Angular app is executed on the server, generating HTML which is sent to the browser. The browser displays a fully rendered page instantly, and then Angular takes over to make it interactive.

Benefits of SSR

• Faster First Contentful Paint (FCP)
• Better SEO (search engines can crawl HTML easily)
• Improved performance on slow networks or devices
• Better user experience

If I am making a Spring Boot REST API + Angular project, how will SSR work instead of Node.js?

Normally, Angular Universal requires a Node.js (Express) server to perform SSR. In a Spring Boot + Angular project:

Option 1: Use Node.js alongside Spring Boot:
   • Spring Boot serves REST APIs (/api/**).
   • Angular Universal runs on Node.js to handle SSR.
   • A reverse proxy (like Nginx) directs frontend routes to Node.js and API routes to Spring Boot.

Option 2: Use Pre-rendering (without Node.js):
   • Angular Universal or Scully can pre-generate static HTML at build time.
   • These static pages can be served directly from Spring Boot.
   • Suitable for static pages but not for dynamic user-specific content.


State Management in Angular

🔹Introduction

State Management in Angular refers to how application data (state) is stored, updated, and shared across components and services.
It ensures consistency, scalability, and predictability, especially as applications grow in complexity.


🔹 Types of State

  1. Local State – Data inside a single component (e.g., form input, toggle button).
    ✅ Managed using component variables.

  2. Shared State – Data shared across multiple components (e.g., logged-in user info, theme preference).
    ✅ Managed using Services + RxJS (BehaviorSubject, ReplaySubject).

  3. Global/Application State – Data needed across the entire app (e.g., authentication, shopping cart, notifications).
    ✅ Managed using state management libraries like NgRx, NGXS, or Akita.


🔹 Common Approaches in Angular

1️⃣ Service with RxJS

  • Use BehaviorSubject or ReplaySubject in a service to hold and emit state.

  • Components subscribe to get updates.

Example – AuthService managing user state:

@Injectable({ providedIn: 'root' }) export class AuthService { private userSubject = new BehaviorSubject<User | null>(null); user$ = this.userSubject.asObservable(); setUser(user: User) { this.userSubject.next(user); } }
  • Any component can subscribe:

this.authService.user$.subscribe(user => console.log(user));

2️⃣ NgRx (Redux Pattern for Angular)

  • Predictable state container using:

    • Actions → What happened (e.g., Login, Logout).

    • Reducers → How the state changes.

    • Store → Single source of truth for the entire app.

  • Best for large & complex applications.

  • Comes with DevTools (time-travel debugging, action logging).


🔹 Why State Management is Important?

✔ Prevents data inconsistency across components.
✔ Makes apps scalable and maintainable.
✔ Simplifies debugging and testing.
✔ Provides a centralized single source of truth.


🔹 Interview-Ready Answer

State management in Angular is about handling and sharing application data consistently.
For small apps, I usually rely on services with RxJS subjects.
For larger applications, I use NgRx, which follows the Redux pattern and provides a single source of truth, predictable state transitions, and better debugging with DevTools.
This ensures data consistency, scalability, and maintainability of the application.