DEV Community

Neer S
Neer S

Posted on

Implement Paging, Sorting, and Searching in API (C#) and angular

Step 1: Implement Paging, Sorting, and Searching Parameters in API (C#)

1. Create a Base Class for API Controllers:

Create a base class BaseApiController that includes properties for paging, sorting, and searching.

public abstract class BaseApiController : ControllerBase
{
    protected int DefaultPageSize { get; } = 10;

    protected int MaxPageSize { get; } = 50;

    protected BaseApiController()
    {
        DefaultPageSize = 10;
        MaxPageSize = 50;
    }

    protected int GetPageSize(int pageSize)
    {
        return pageSize > MaxPageSize ? MaxPageSize : pageSize;
    }

    protected int GetPageNumber(int pageNumber)
    {
        return pageNumber < 1 ? 1 : pageNumber;
    }
}
Enter fullscreen mode Exit fullscreen mode

2. Create a Model for Request Parameters:

Create a model to hold the paging, sorting, and searching parameters.

public class QueryParameters
{
    public int PageNumber { get; set; } = 1;

    private int _pageSize = 10;
    public int PageSize
    {
        get => _pageSize;
        set => _pageSize = value > 50 ? 50 : value;
    }

    public string SortBy { get; set; }

    public string SearchTerm { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Use Parameters in API Controller:

Use these parameters in your API controllers to filter and paginate data.

[Route("api/[controller]")]
[ApiController]
public class ProductsController : BaseApiController
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpGet]
    public IActionResult GetProducts([FromQuery] QueryParameters parameters)
    {
        var products = _productService.GetProducts(parameters);

        return Ok(products);
    }
}
Enter fullscreen mode Exit fullscreen mode

Implement Pagination, Sorting, and Searching in Service:

Implement the actual logic in your service layer to apply these parameters to your data queries.

public interface IProductService
{
    IEnumerable<Product> GetProducts(QueryParameters parameters);
}
Enter fullscreen mode Exit fullscreen mode
public class ProductService : IProductService
{
    private readonly AppDbContext _dbContext;

    public ProductService(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IEnumerable<Product> GetProducts(QueryParameters parameters)
    {
        var query = _dbContext.Products.AsQueryable();

        // Filtering
        if (!string.IsNullOrWhiteSpace(parameters.SearchTerm))
        {
            query = query.Where(p => p.Name.Contains(parameters.SearchTerm));
        }

        // Sorting
        if (!string.IsNullOrWhiteSpace(parameters.SortBy))
        {
            query = query.OrderByDynamic(parameters.SortBy);
        }

        // Paging
        var skipAmount = (parameters.PageNumber - 1) * parameters.PageSize;
        query = query.Skip(skipAmount).Take(parameters.PageSize);

        return query.ToList();
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Angular 14 Frontend

Create Angular Service:

Create a service to interact with the API.

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

@Injectable({
  providedIn: 'root'
})
export class ProductService {
  private apiUrl = 'https://localhost:5001/api/products';

  constructor(private http: HttpClient) { }

  getProducts(pageNumber: number, pageSize: number, sortBy: string, searchTerm: string): Observable<Product[]> {
    let params = new HttpParams()
      .set('pageNumber', pageNumber.toString())
      .set('pageSize', pageSize.toString())
      .set('sortBy', sortBy)
      .set('searchTerm', searchTerm);

    return this.http.get<Product[]>(this.apiUrl, { params });
  }
}
Enter fullscreen mode Exit fullscreen mode

Create Angular Component:

Create a component to display and interact with the data.

import { Component, OnInit } from '@angular/core';
import { ProductService } from './product.service';
import { Product } from './product.model';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit {
  products: Product[] = [];
  pageNumber = 1;
  pageSize = 10;
  sortBy = '';
  searchTerm = '';

  constructor(private productService: ProductService) { }

  ngOnInit(): void {
    this.loadProducts();
  }

  loadProducts(): void {
    this.productService.getProducts(this.pageNumber, this.pageSize, this.sortBy, this.searchTerm)
      .subscribe(products => {
        this.products = products;
      });
  }

  onPageChange(page: number): void {
    this.pageNumber = page;
    this.loadProducts();
  }

  onSortChange(sortBy: string): void {
    this.sortBy = sortBy;
    this.loadProducts();
  }

  onSearch(searchTerm: string): void {
    this.searchTerm = searchTerm;
    this.loadProducts();
  }
}
Enter fullscreen mode Exit fullscreen mode

HTML Template for Component:

Create an HTML template to display the products, pagination controls, sorting options, and search input.

<div>
  <input type="text" placeholder="Search..." (input)="onSearch($event.target.value)" />

  <select (change)="onSortChange($event.target.value)">
    <option value="">Sort By</option>
    <option value="name">Name</option>
    <option value="price">Price</option>
  </select>

  <ul>
    <li *ngFor="let product of products">
      {{ product.name }} - {{ product.price }}
    </li>
  </ul>

  <div>
    <button (click)="onPageChange(pageNumber - 1)" [disabled]="pageNumber === 1">Previous</button>
    <span>Page {{ pageNumber }}</span>
    <button (click)="onPageChange(pageNumber + 1)">Next</button>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Explanation:

In this setup, the Angular component ProductListComponent interacts with the ProductService to fetch products from the API.
The component includes methods to handle paging, sorting, and searching actions, which in turn call the appropriate methods in the service.

The API controller ProductsController receives the query parameters from the frontend and passes them to the ProductService to filter, sort, and paginate the data.

The ProductService implements the actual logic to apply these parameters to the LINQ queries against the Product entities.

Notes:
This is a basic example. You may need to adjust the code according to your specific requirements.
For sorting, you might want to add options for ascending and descending order.
For searching, you may want to implement more complex search criteria depending on your data model.
Error handling, validation, and security considerations are important aspects to add in a production-ready application.

This code provides a foundation for reusable paging, sorting, and searching features in your .NET Core 6 API with an Angular 14 frontend.

Top comments (0)