dstpabuaran.com/docs/2026-08-14-lazy-loading-card-table.md

2.4 KiB

Lazy Loading Card Table

Date

2026-08-14

Goal

Optimize page load performance for raw materials, products, and purchases list pages by implementing lazy loading for child/variant data in card-based layouts.

Problem

Pages with 100+ records loaded all child data eagerly (variants, items), causing slow initial page loads.

Solution Pattern

  1. Backend: Remove eager-loaded relationships from paginated query
  2. Backend: Add SQL subqueries for summary data (variants_count, total_qty, material_name, unit)
  3. Backend: Add new controller method returning JSON for lazy load
  4. Frontend: Use useCardTableExpand(false) for default collapsed state
  5. Frontend: Fetch child data via fetch() on expand, store in Record<number, T[]> state
  6. Frontend: Pass items + isLoading props to sub-row components

Files Modified

Purchases (this session)

  • app/Services/Admin/Manage/PurchaseService.php - paginated() no longer eager loads purchaseItems; added getItems() method
  • app/Http/Controllers/Admin/Manage/PurchaseController.php - added items() method
  • routes/web.php - added GET purchases/{purchase}/items route
  • resources/js/pages/admin/manage/purchase/columns.tsx - Purchase type: variants_count, total_qty, material_name, unit
  • resources/js/pages/admin/manage/purchase/purchase-card.tsx - uses summary data from props
  • resources/js/pages/admin/manage/purchase/purchase-sub-row.tsx - accepts items & isLoading props
  • resources/js/pages/admin/manage/purchase/index.tsx - lazy loading with fetchItems()

Raw Materials & Products (previous sessions)

  • Same pattern applied to RawMaterialService, RawMaterialController, ProductService, ProductController
  • Frontend pages updated with lazy loading state

Route Added

Route::get('purchases/{purchase}/items', [PurchaseController::class, 'items'])->name('purchases.items')->middleware('permission:purchases.view');

Key Implementation Details

  • SQL subqueries avoid N+1 queries while keeping summary data in the paginated response
  • getItems() method handles media URL resolution for item photos
  • Frontend caches loaded items to avoid re-fetching on repeated expand/collapse
  • Loading state shown while items are being fetched

Verification

  • PHP syntax check: OK
  • TypeScript: Only pre-existing errors in use-purchase-draft.ts (unrelated)
  • Route cache cleared