custom_ui/frontend/documentation/LOADING_USAGE.md

5.0 KiB

Global Loading State Usage Guide

This document explains how to use the global loading state system in your Vue app.

Overview

The loading system provides multiple ways to handle loading states:

  1. Global Loading Overlay - Shows over the entire app
  2. Component-specific Loading - For individual components like DataTable and Form
  3. Operation-specific Loading - For tracking specific async operations

Loading Store

Basic Usage

import { useLoadingStore } from "../../stores/loading";

const loadingStore = useLoadingStore();

// Set global loading
loadingStore.setLoading(true, "Processing...");

// Set component-specific loading
loadingStore.setComponentLoading("dataTable", true, "Loading data...");

// Use async wrapper
const data = await loadingStore.withLoading(
  "fetchUsers",
  () => Api.getUsers(),
  "Fetching user data...",
);

Available Methods

  • setLoading(isLoading, message?) - Global loading state
  • setComponentLoading(componentName, isLoading, message?) - Component loading
  • startOperation(operationKey, message?) - Start tracked operation
  • stopOperation(operationKey) - Stop tracked operation
  • withLoading(operationKey, asyncFn, message?) - Async wrapper
  • withComponentLoading(componentName, asyncFn, message?) - Component async wrapper

Convenience Methods

  • startApiCall(apiName?) - Quick API loading
  • stopApiCall() - Stop API loading
  • startDataTableLoading(message?) - DataTable loading
  • stopDataTableLoading() - Stop DataTable loading
  • startFormLoading(message?) - Form loading
  • stopFormLoading() - Stop Form loading

DataTable Component

The DataTable component automatically integrates with the loading store:

<template>
  <DataTable
    :data="tableData"
    :columns="columns"
    tableName="clients"
    :loading="customLoading"
    loadingMessage="Custom loading message..."
    emptyMessage="No clients found"
  />
</template>

<script setup>
// DataTable will automatically show loading when:
// 1. props.loading is true
// 2. Global loading store has loading for 'dataTable'
// 3. Global loading store has loading for props.tableName
// 4. Any global loading (if useGlobalLoading is true)

// You can also control it directly:
const tableRef = ref();
tableRef.value?.startLoading("Custom loading...");
tableRef.value?.stopLoading();
</script>

Form Component

The Form component also integrates with loading:

<template>
  <Form
    :fields="formFields"
    formName="userForm"
    :loading="customLoading"
    loadingMessage="Saving user..."
    @submit="handleSubmit"
  />
</template>

<script setup>
// Form will disable all inputs and show loading buttons when:
// 1. props.loading is true
// 2. Global loading store has loading for 'form'
// 3. Global loading store has loading for props.formName
// 4. Internal isSubmitting is true

// Control directly:
const formRef = ref();
formRef.value?.startLoading("Processing...");
formRef.value?.stopLoading();
</script>

API Integration Example

// In your page component
import { useLoadingStore } from "../../stores/loading";

const loadingStore = useLoadingStore();

// Method 1: Manual control
const loadData = async () => {
  try {
    loadingStore.startDataTableLoading("Loading clients...");
    const data = await Api.getClients();
    tableData.value = data;
  } finally {
    loadingStore.stopDataTableLoading();
  }
};

// Method 2: Using wrapper (recommended)
const loadData = async () => {
  const data = await loadingStore.withComponentLoading(
    "clients",
    () => Api.getClients(),
    "Loading clients...",
  );
  tableData.value = data;
};

// Method 3: For global overlay
const performGlobalAction = async () => {
  const result = await loadingStore.withLoading(
    "globalOperation",
    () => Api.performHeavyOperation(),
    "Processing your request...",
  );
  return result;
};

Global Loading Overlay

The GlobalLoadingOverlay component shows automatically when global loading is active:

<!-- Already added to App.vue -->
<GlobalLoadingOverlay />

<!-- Customizable props -->
<GlobalLoadingOverlay
    :globalOnly="false"  <!-- Show for any loading, not just global -->
    :minDisplayTime="500"  <!-- Minimum display time in ms -->
/>

Best Practices

  1. Use component-specific loading for individual components
  2. Use global loading for app-wide operations (login, navigation, etc.)
  3. Use operation tracking for multiple concurrent operations
  4. Always use try/finally when manually controlling loading
  5. Prefer async wrappers over manual start/stop calls
  6. Provide meaningful loading messages to users

Error Handling

const loadData = async () => {
  try {
    const data = await loadingStore.withComponentLoading(
      "clients",
      () => Api.getClients(),
      "Loading clients...",
    );
    tableData.value = data;
  } catch (error) {
    console.error("Failed to load clients:", error);
    // Show error message to user
    // Loading state is automatically cleared by the wrapper
  }
};