← Back to Articles         
How would you share logged-in user information across components?

How would you share logged-in user information across components?

Published on 02 Oct 2026     7 min read Angular
Scenario Based Questions

Below are interview-focused answers for an Angular + ASP.NET Core Web API application.

1. How would you share logged-in user information across components?

Use a singleton authentication/user service to maintain the logged-in user's state. In modern Angular, Signals are a simple choice for application-wide user state.

Angular model

export interface User {
  id: number;
  name: string;
  email: string;
  role: string;
}

auth.service.ts

import { Injectable, computed, signal } from '@angular/core';
import { User } from './user';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  private currentUserSignal = signal<User | null>(null);

  currentUser = this.currentUserSignal.asReadonly();

  isLoggedIn = computed(() => this.currentUserSignal() !== null);

  setUser(user: User) {
    this.currentUserSignal.set(user);
  }

  logout() {
    this.currentUserSignal.set(null);
  }
}

Because the service uses:

providedIn: 'root'

the same service instance is shared across the application.

Header component

import { Component, inject } from '@angular/core';
import { AuthService } from './auth.service';

@Component({
  selector: 'app-header',
  standalone: true,
  template: `
    @if (auth.currentUser(); as user) {
      <span>Welcome {{ user.name }}</span>
    }
  `
})
export class Header {

  auth = inject(AuthService);
}

Profile component

export class Profile {

  auth = inject(AuthService);
}
@if (auth.currentUser(); as user) {
  <h2>{{ user.name }}</h2>
  <p>{{ user.email }}</p>
}

Both components automatically see changes to the same user state.

Important architecture

Login Component
      |
      | Login
      ↓
ASP.NET Core API
      |
      | JWT / User Information
      ↓
AuthService
      |
      | Signal<User>
      ↓
-----------------------------
|            |              |
Header     Profile        Admin

For security, Angular's user state is not authoritative. ASP.NET Core must still authenticate the JWT and enforce authorization on protected API endpoints.

Interview answer:

I normally maintain logged-in user state in a root-level authentication service. Components consume the shared state using Signals or Observables. However, actual authentication and authorization are always enforced by ASP.NET Core.


2. How would you implement pagination using Angular and ASP.NET Core?

Pagination should normally be server-side for large datasets.

Instead of retrieving 100,000 records and paginating them in Angular:

GET /api/articles

send pagination parameters:

GET /api/articles?page=2&pageSize=10

ASP.NET Core

[HttpGet]
public async Task<IActionResult> GetArticles(
    int page = 1,
    int pageSize = 10)
{
    var query = _context.Articles
        .AsNoTracking()
        .OrderByDescending(x => x.CreatedOn);

    var totalCount = await query.CountAsync();

    var articles = await query
        .Skip((page - 1) * pageSize)
        .Take(pageSize)
        .ToListAsync();

    return Ok(new
    {
        items = articles,
        totalCount,
        page,
        pageSize
    });
}

The key calculation is:

Skip((page - 1) * pageSize)
Take(pageSize)

For page 3 with 10 records per page:

Skip = (3 - 1) × 10
     = 20

Take = 10

So SQL effectively returns records 21–30.

Angular service

getArticles(page: number, pageSize: number) {

  return this.http.get<any>(
    `${this.apiUrl}?page=${page}&pageSize=${pageSize}`
  );
}

Component

articles: Article[] = [];

page = 1;
pageSize = 10;
totalCount = 0;

loadArticles() {

  this.articleService
      .getArticles(this.page, this.pageSize)
      .subscribe(response => {

        this.articles = response.items;
        this.totalCount = response.totalCount;

      });
}

nextPage() {
  this.page++;
  this.loadArticles();
}

previousPage() {
  if (this.page > 1) {
    this.page--;
    this.loadArticles();
  }
}

Flow

Angular
   |
   | GET ?page=2&pageSize=10
   ↓
ASP.NET Core
   |
   | Count()
   | Skip(10)
   | Take(10)
   ↓
SQL Server
   |
   ↓
{
   items: [...],
   totalCount: 125,
   page: 2,
   pageSize: 10
}
   |
   ↓
Angular Pagination UI

Interview answer:

I prefer server-side pagination. Angular sends page and pageSize, and ASP.NET Core uses Skip() and Take() to retrieve only the required records. The API also returns the total count so Angular can calculate the number of pages.


3. How would you implement search and filtering?

Search and filtering should also normally be performed server-side when dealing with database data.

For example:

GET /api/articles?search=angular&categoryId=5&page=1&pageSize=10

ASP.NET Core

[HttpGet]
public async Task<IActionResult> GetArticles(
    string? search,
    int? categoryId,
    int page = 1,
    int pageSize = 10)
{
    var query = _context.Articles
        .AsNoTracking()
        .AsQueryable();

    if (!string.IsNullOrWhiteSpace(search))
    {
        query = query.Where(x =>
            x.Title.Contains(search));
    }

    if (categoryId.HasValue)
    {
        query = query.Where(x =>
            x.CategoryId == categoryId);
    }

    var totalCount = await query.CountAsync();

    var articles = await query
        .OrderByDescending(x => x.CreatedOn)
        .Skip((page - 1) * pageSize)
        .Take(pageSize)
        .ToListAsync();

    return Ok(new
    {
        items = articles,
        totalCount
    });
}

Angular

search = '';
categoryId: number | null = null;

loadArticles() {

  let params: any = {
    page: this.page,
    pageSize: this.pageSize
  };

  if (this.search) {
    params.search = this.search;
  }

  if (this.categoryId) {
    params.categoryId = this.categoryId;
  }

  this.http.get<any>(
    '/api/articles',
    { params }
  )
  .subscribe(response => {
    this.articles = response.items;
    this.totalCount = response.totalCount;
  });
}

When the filter changes, reset pagination:

onSearch() {
  this.page = 1;
  this.loadArticles();
}

A common improvement for text search is debouncing:

searchControl.valueChanges
  .pipe(
    debounceTime(300),
    distinctUntilChanged()
  )
  .subscribe(search => {
    this.search = search ?? '';
    this.page = 1;
    this.loadArticles();
  });

This prevents an API call for every keystroke.

User types:

A
An
Ang
Angu
Angular

Without debounce
↓
5 API requests

With debounce
↓
wait ~300ms
↓
1 API request

Interview answer:

I send search and filter values as query-string parameters to ASP.NET Core. The backend dynamically builds an EF Core IQueryable, applies filters, then pagination. For text boxes, I normally use RxJS debounceTime() and distinctUntilChanged() to avoid unnecessary API calls.


4. How would you implement infinite scrolling?

Infinite scrolling is similar to pagination, but instead of displaying Next/Previous buttons, Angular automatically loads the next batch when the user approaches the bottom of the page.

For example:

Initial request
GET /api/articles?page=1&pageSize=10

User scrolls down
GET /api/articles?page=2&pageSize=10

Scrolls again
GET /api/articles?page=3&pageSize=10

ASP.NET Core API

The same pagination endpoint can be reused:

[HttpGet]
public async Task<IActionResult> GetArticles(
    int page = 1,
    int pageSize = 10)
{
    var query = _context.Articles
        .AsNoTracking()
        .OrderByDescending(x => x.CreatedOn);

    var totalCount = await query.CountAsync();

    var articles = await query
        .Skip((page - 1) * pageSize)
        .Take(pageSize)
        .ToListAsync();

    return Ok(new
    {
        items = articles,
        totalCount
    });
}

The main difference is in Angular.

Angular component

articles: Article[] = [];

page = 1;
pageSize = 10;

loading = false;
hasMore = true;

loadMore() {

  if (this.loading || !this.hasMore)
    return;

  this.loading = true;

  this.articleService
      .getArticles(this.page, this.pageSize)
      .subscribe(response => {

        this.articles = [
          ...this.articles,
          ...response.items
        ];

        if (response.items.length < this.pageSize) {
          this.hasMore = false;
        } else {
          this.page++;
        }

        this.loading = false;
      });
}

The important difference from normal pagination is this:

Normal pagination

this.articles = response.items;

Existing records are replaced.

Infinite scrolling

this.articles = [
  ...this.articles,
  ...response.items
];

New records are appended.

So:

Page 1
[A B C D]

        ↓ Scroll

Page 2
[E F G H]

Angular array
[A B C D E F G H]

        ↓ Scroll

Page 3
[I J K L]

Angular array
[A B C D E F G H I J K L]

For the browser-side trigger, IntersectionObserver is preferable to continuously handling raw scroll events.

For example, place a sentinel at the bottom:

@for (article of articles; track article.id) {
  <app-article [article]="article" />
}

<div #loadMoreTrigger></div>

When that element enters the viewport:

observer = new IntersectionObserver(entries => {

  if (entries[0].isIntersecting) {
    this.loadMore();
  }

});

Search + filter + infinite scroll

When the user changes the search/filter criteria, reset the accumulated state:

applyFilter() {

  this.page = 1;
  this.articles = [];
  this.hasMore = true;

  this.loadMore();
}

Otherwise, results from the old filter can be mixed with the new results.


How all four concepts work together

A production Angular + ASP.NET Core application could use:

Angular
│
├── AuthService
│     └── Signal<User>
│
├── Article Component
│
├── Search
│     └── debounceTime()
│
├── Filters
│     ├── Category
│     └── Tag
│
└── Pagination / Infinite Scroll
          │
          ↓
ASP.NET Core Web API
          │
          ├── Authentication
          ├── Authorization
          ├── Search
          ├── Filtering
          ├── Sorting
          └── Pagination
                 │
                 ↓
             EF Core
                 │
                 ↓
             SQL Server

Key interview points

Requirement Recommended approach
Share logged-in user Root service + Signal/Observable
Security Enforce authentication/authorization in ASP.NET Core
Pagination Server-side Skip() + Take()
Search Server-side query
Filters Query-string parameters
Search typing debounceTime()
Multiple filters Build an IQueryable dynamically
Infinite scrolling Reuse paginated API
Detect bottom IntersectionObserver
Infinite-scroll results Append instead of replace
New search/filter Reset page and accumulated results
Large datasets Don't load everything into Angular

Interview summary

Logged-in user: Store shared client-side user state in a root-level Angular service using Signals or Observables.

Pagination: Send page and pageSize to ASP.NET Core and use EF Core Skip() and Take().

Search/filtering: Pass criteria as query parameters and perform filtering server-side before pagination. Debounce text search in Angular.

Infinite scrolling: Reuse the paginated API, detect when the user reaches the bottom using IntersectionObserver, request the next page, and append the returned records to the existing collection.

← Back to Articles