# AutoComplete

## AutoComplete

> Learn how to use AutoComplete input type for searching and selecting from large datasets with real-time filtering. AutoComplete provides a better user experience than dropdowns when dealing with large lists of options.

A comprehensive guide for using AutoComplete in form configurations. This guide covers how to configure AutoComplete inputs with remote data, local options, filtering, and custom configurations.

***

### Overview

The `FormInputType.autocomplete` allows you to:

1. **Search large datasets** - Efficiently search through hundreds or thousands of options
2. **Real-time filtering** - Filter options as the user types
3. **Remote data loading** - Load options from API endpoints dynamically
4. **Better UX for large lists** - Provide a better experience than dropdowns for large option sets
5. **Customizable search behavior** - Configure minimum characters, delay, and search parameters

***

### Use Case 1: AutoComplete with Remote Data

#### Scenario

You have a large list of users and want users to search and select a user efficiently. Instead of loading all users upfront, you want to search them dynamically from the API.

#### Configuration

```typescript
import { FormInput, FormInputType } from '@tradinos/cms-frontend-form';

{
  key: 'user_id',
  label: 'users',
  inputType: FormInputType.autocomplete,
  value: project?.user_id,
  // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
  // TypeScript interface is AutoCompleteConfiguration (PascalCase)
  autoCompleteConfiguration: {
    showClear: true,
    filter: true,
    filterBy: 'name',
    optionLabel: 'name',
    valueBy: 'id',
    remoteDataConfiguration: {
      endPoint: 'user',
      queryParams: {limit: 50},
      mapHttpResponse: (response: any) => {
        const data = Array.isArray(response.data) ? response.data : [];
        return data.map((item: any) => ({
          name: item.name,
          id: item.id
        }));
      },
    },
    minLength: 2,
    delay: 300,
    placeholder: 'Search users...',
  }
}
```

#### Example from Codebase

**File:** `src/app/dashboard/project/services/project.service.ts` (lines 82-101)

```typescript
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class ProjectService extends EntityService<Project> {
  constructor(private http: HttpClient) {
    super();
  }

  override manualInputsFn = async (project?: Project) => {
    return [
      {
        key: 'user_id',
        label: 'users',
        inputType: FormInputType.autocomplete,
        value: project?.user_id,
        // AutoComplete Configuration
        // See documentation: docs/[Frontend] Form/AutoComplete.md
        // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
        // TypeScript interface is AutoCompleteConfiguration (PascalCase)
        autoCompleteConfiguration: {
          showClear: true,
          filter: true,
          filterBy: 'name',
          optionLabel: 'name',
          valueBy: 'id',
          // Load users from API using async manualInputsFn
          // See documentation: docs/[Frontend] Form/Async Manual Inputs.md
          options: await this.loadUsersFromAPI(),
          minLength: 1,
          placeholder: 'Search users...',
        }
      },
    ] as FormInput<Project>[];
  }

  // Load users from API for AutoComplete
  private async loadUsersFromAPI(): Promise<Array<{name: string, id: string}>> {
    try {
      const response = await firstValueFrom(
        this.http.get<any>('user', { params: { limit: 100 } })
      );
      const users = Array.isArray(response.data) ? response.data : [];
      return users.map((user: any) => ({
        name: user.name || user.username || user.email || 'Unknown',
        id: user.id || user.user_id || user._id
      }));
    } catch (error) {
      console.warn('Failed to load users from API:', error);
      return [];
    }
  }
}
```

#### Parameters Explained

| Parameter                                           | Type                         | Description                                                                                                                                                                     | Required |
| --------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `inputType`                                         | `FormInputType.autocomplete` | Specifies AutoComplete input type                                                                                                                                               | ✅ Yes    |
| `autoCompleteConfiguration`                         | `AutoCompleteConfiguration`  | Configuration object for AutoComplete. **Note:** Property name is `autoCompleteConfiguration` (camelCase), but TypeScript interface is `AutoCompleteConfiguration` (PascalCase) | ✅ Yes    |
| `autoCompleteConfiguration.optionLabel`             | `string`                     | Property name to display in options                                                                                                                                             | ✅ Yes    |
| `autoCompleteConfiguration.valueBy`                 | `string`                     | Property name to use as value                                                                                                                                                   | ✅ Yes    |
| `autoCompleteConfiguration.filterBy`                | `string`                     | Property name to filter by                                                                                                                                                      | Optional |
| `autoCompleteConfiguration.showClear`               | `boolean`                    | Show clear button                                                                                                                                                               | Optional |
| `autoCompleteConfiguration.filter`                  | `boolean`                    | Enable filtering                                                                                                                                                                | Optional |
| `autoCompleteConfiguration.options`                 | `any[]`                      | Array of local options (use with async manualInputsFn)                                                                                                                          | Optional |
| `autoCompleteConfiguration.remoteDataConfiguration` | `object`                     | Configuration for remote data loading                                                                                                                                           | Optional |
| `autoCompleteConfiguration.minLength`               | `number`                     | Minimum characters before search                                                                                                                                                | Optional |
| `autoCompleteConfiguration.delay`                   | `number`                     | Delay in milliseconds before search                                                                                                                                             | Optional |
| `autoCompleteConfiguration.placeholder`             | `string`                     | Placeholder text                                                                                                                                                                | Optional |

**⚠️ Important Note on Property Name:**

* In your code, use `autoCompleteConfiguration` (camelCase with capital C)
* The TypeScript interface type is `AutoCompleteConfiguration` (PascalCase)
* This follows TypeScript/JavaScript naming conventions where property names are camelCase and type names are PascalCase

#### How it Works

1. **User Types**: User starts typing in the AutoComplete field
2. **Minimum Length Check**: After `minLength` characters (e.g., 2), search is triggered
3. **Delay**: Waits for `delay` milliseconds (e.g., 300ms) to avoid excessive API calls
4. **API Call**: Makes request to `endPoint` with search query
5. **Response Mapping**: Maps API response using `mapHttpResponse` function
6. **Display Options**: Shows filtered options matching the search query
7. **Selection**: User selects an option, value is set using `valueBy` property

***

### Use Case 2: AutoComplete with Local Options

#### Scenario

You have a smaller, predefined list of options that you want to load upfront and filter locally.

#### Configuration

```typescript
override manualInputsFn = async (project?: Project) => {
  // Load options upfront
  const categories = await this.loadCategories();

  return [
    {
      key: 'category_id',
      label: 'Category',
      inputType: FormInputType.autocomplete,
      value: project?.category_id,
      // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
      autoCompleteConfiguration: {
        showClear: true,
        filter: true,
        filterBy: 'name',
        optionLabel: 'name',
        valueBy: 'id',
        options: categories,  // Local options array
        minLength: 1,
        placeholder: 'Type to search categories...',
      }
    },
  ] as FormInput<Project>[];
}
```

#### How it Works

1. **Load Options**: Options are loaded upfront (synchronously or asynchronously)
2. **Local Filtering**: As user types, options are filtered locally
3. **No API Calls**: No additional API calls needed during typing
4. **Faster Response**: Instant filtering without network delay

***

### Use Case 3: AutoComplete with Custom Search Logic

#### Scenario

You need custom search logic that searches multiple fields or applies complex filtering.

#### Configuration

```typescript
{
  key: 'product_id',
  label: 'Product',
  inputType: FormInputType.autocomplete,
  // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
  autoCompleteConfiguration: {
    optionLabel: 'name',
    valueBy: 'id',
    remoteDataConfiguration: {
      endPoint: 'products',
      queryParams: (query: string) => ({
        search: query,
        limit: 50,
        include: 'category,manufacturer'
      }),
      mapHttpResponse: (response: any) => {
        const data = Array.isArray(response.data) ? response.data : [];
        return data.map((item: any) => ({
          name: `${item.name} - ${item.category?.name}`,
          id: item.id,
          description: item.description,
          manufacturer: item.manufacturer?.name
        }));
      },
    },
    minLength: 3,
    delay: 500,
  }
}
```

***

### Complete Examples

#### Example 1: AutoComplete with Local Options Loaded from API (Real Implementation)

This example shows a real implementation from the codebase where users are loaded from API and used in AutoComplete with local filtering.

**File:** `src/app/dashboard/project/services/project.service.ts` (lines 82-101)

```typescript
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { EntityService } from '@tradinos/cms-frontend-entity';
import { FormInput, FormInputType } from '@tradinos/cms-frontend-form';
import { Project } from './project.model';
import { firstValueFrom } from 'rxjs';

@Injectable()
export class ProjectService extends EntityService<Project> {
  constructor(private http: HttpClient) {
    super();
  }

  override manualInputsFn = async (project?: Project) => {
    return [
      {
        key: 'user_id',
        label: 'users',
        inputType: FormInputType.autocomplete,
        value: project?.user_id,
        // AutoComplete Configuration
        // See documentation: docs/[Frontend] Form/AutoComplete.md
        // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
        // TypeScript interface is AutoCompleteConfiguration (PascalCase)
        autoCompleteConfiguration: {
          showClear: true,
          filter: true,
          filterBy: 'name',
          optionLabel: 'name',
          valueBy: 'id',
          // Load users from API using async manualInputsFn
          // See documentation: docs/[Frontend] Form/Async Manual Inputs.md
          options: await this.loadUsersFromAPI(),
          minLength: 1,
          placeholder: 'Search users...',
        }
      },
    ] as FormInput<Project>[];
  }

  // Load users from API for AutoComplete
  private async loadUsersFromAPI(): Promise<Array<{name: string, id: string}>> {
    try {
      const response = await firstValueFrom(
        this.http.get<any>('user', { params: { limit: 100 } })
      );
      const users = Array.isArray(response.data) ? response.data : [];
      return users.map((user: any) => ({
        name: user.name || user.username || user.email || 'Unknown',
        id: user.id || user.user_id || user._id
      }));
    } catch (error) {
      console.warn('Failed to load users from API:', error);
      return [];
    }
  }
}
```

**Result:**

* Users are loaded from API when form opens
* User types "John" → Local filter searches through loaded users
* Shows filtered results: "John Doe", "John Smith", etc.
* User selects a user → `user_id` is set to selected user's ID

**Key Points:**

* Uses `async manualInputsFn` to load users before form renders
* Uses `autoCompleteConfiguration` (note the capital C) property name
* Options are loaded once and filtered locally (no API calls while typing)
* Better for smaller datasets (< 100 items) where loading all options is acceptable

***

#### Example 2: AutoComplete with Local Options

```typescript
override manualInputsFn = (project?: Project) => {
  const statusOptions = [
    {name: 'Draft', id: 'draft'},
    {name: 'In Progress', id: 'in_progress'},
    {name: 'Review', id: 'review'},
    {name: 'Completed', id: 'completed'},
    {name: 'Archived', id: 'archived'},
  ];

  return [
    {
      key: 'status',
      label: 'Status',
      inputType: FormInputType.autocomplete,
      value: project?.status,
      // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
      autoCompleteConfiguration: {
        showClear: true,
        filter: true,
        filterBy: 'name',
        optionLabel: 'name',
        valueBy: 'id',
        options: statusOptions,
        minLength: 1,
        placeholder: 'Type to filter status...',
      }
    },
  ] as FormInput<Project>[];
}
```

***

#### Example 3: AutoComplete with Multiple Fields Display

```typescript
{
  key: 'user_id',
  label: 'Assigned User',
  inputType: FormInputType.autocomplete,
  // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
  autoCompleteConfiguration: {
    optionLabel: (item: any) => `${item.name} (${item.email})`,
    valueBy: 'id',
    remoteDataConfiguration: {
      endPoint: 'user',
      queryParams: {limit: 50},
      mapHttpResponse: (response: any) => {
        return response.data.map((item: any) => ({
          name: item.name,
          email: item.email,
          id: item.id,
          department: item.department?.name
        }));
      },
    },
    minLength: 2,
    delay: 300,
  }
}
```

***

### Comparison Table

| Feature             | AutoComplete                | Dropdown                    |
| ------------------- | --------------------------- | --------------------------- |
| **Best for**        | Large datasets (100+ items) | Small datasets (< 50 items) |
| **Search**          | ✅ Real-time search          | ⚠️ Filter only (if enabled) |
| **Performance**     | ✅ Efficient for large lists | ❌ Slow with large lists     |
| **User Experience** | ✅ Type to search            | ⚠️ Scroll to find           |
| **Remote Data**     | ✅ Optimized for remote      | ✅ Supports remote           |
| **Loading**         | ✅ Lazy loading              | ⚠️ Loads all options        |

***

### Best Practices

1. **Use AutoComplete for large lists**: When you have more than 50-100 options, AutoComplete provides better UX
2. **Set appropriate minLength**: Require at least 2-3 characters before searching to reduce API calls

   ```typescript
   minLength: 2  // Good for most cases
   minLength: 3  // Better for very large datasets
   ```
3. **Add delay for remote searches**: Prevent excessive API calls with a delay

   ```typescript
   delay: 300  // 300ms delay is usually optimal
   ```
4. **Use remoteDataConfiguration for large datasets**: Don't load all options upfront

   ```typescript
   remoteDataConfiguration: {
     endPoint: 'categories',
     queryParams: {limit: 100}
   }
   ```
5. **Provide helpful placeholders**: Guide users on what to search for

   ```typescript
   placeholder: 'Search categories...'
   ```
6. **Map API responses properly**: Ensure response format matches expected structure

   ```typescript
   mapHttpResponse: (response: any) => {
     return response.data.map(item => ({
       name: item.name,
       id: item.id
     }));
   }
   ```
7. **Enable showClear for optional fields**: Allow users to easily clear selection

   ```typescript
   showClear: true
   ```

***

### Common Patterns

#### Pattern 1: Simple Remote AutoComplete

```typescript
{
  key: 'category_id',
  inputType: FormInputType.autocomplete,
  // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
  autoCompleteConfiguration: {
    optionLabel: 'name',
    valueBy: 'id',
    remoteDataConfiguration: {
      endPoint: 'categories',
    },
    minLength: 2,
  }
}
```

#### Pattern 2: AutoComplete with Custom Query Params

```typescript
{
  key: 'product_id',
  inputType: FormInputType.autocomplete,
  // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
  autoCompleteConfiguration: {
    optionLabel: 'name',
    valueBy: 'id',
    remoteDataConfiguration: {
      endPoint: 'products',
      queryParams: (query: string) => ({
        q: query,
        status: 'active',
        limit: 50
      }),
    },
    minLength: 2,
    delay: 300,
  }
}
```

#### Pattern 3: AutoComplete with Local Options

```typescript
{
  key: 'status',
  inputType: FormInputType.autocomplete,
  // Note: Property name is autoCompleteConfiguration (camelCase with capital C)
  autoCompleteConfiguration: {
    optionLabel: 'name',
    valueBy: 'id',
    options: [
      {name: 'Active', id: 'active'},
      {name: 'Inactive', id: 'inactive'},
    ],
    minLength: 1,
  }
}
```

***

### Related Documentation

* Dropdown Configuration - Learn about dropdown inputs
* Async Manual Inputs - Understand async data loading
* Form Input Types - See all available input types

***

### Summary

AutoComplete provides an efficient way to search and select from large datasets:

* **Remote data support**: Load options dynamically from API
* **Real-time filtering**: Filter options as user types
* **Configurable search**: Set minimum characters, delay, and search parameters
* **Better UX**: Ideal for large lists (100+ items)
* **Flexible configuration**: Support both remote and local options

This feature enables efficient searching and selection in forms, especially when dealing with large option sets that would be impractical to display in a dropdown.
