# Infinite Lookup List

When the list of options is too large to load at once, use the `infinite` flag to enable paged loading. As the user scrolls, additional pages are fetched automatically.

```tsx
import { createModel } from "cx/data";
import { Controller, LabelsTopLayout } from "cx/ui";
import { isString } from "cx/util";
import { LookupField } from "cx/widgets";

interface City {
  id: number;
  text: string;
}

interface Model {
  selectedCities: City[];
}

const m = createModel<Model>();

// Generate fake city database
const cityNames = [
  "New York",
  "Los Angeles",
  "Chicago",
  "Houston",
  "Phoenix",
  "Philadelphia",
  "San Antonio",
  "San Diego",
  "Dallas",
  "San Jose",
  "Austin",
  "Jacksonville",
  "Fort Worth",
  "Columbus",
  "Charlotte",
  "Seattle",
  "Denver",
  "Boston",
  "El Paso",
  "Detroit",
  "Nashville",
  "Memphis",
  "Portland",
  "Baltimore",
];

const cityDb: City[] = Array.from({ length: 5000 }, (_, i) => ({
  id: i,
  text: `${cityNames[i % cityNames.length]} ${i}`.trim(),
})).sort((a, b) => a.text.localeCompare(b.text));


class PageController extends Controller {
  onQueryPage(params: { query: string; pageSize: number; page: number }) {
    let { query, pageSize, page } = params;
    let regex = new RegExp(query, "gi");
    let filtered = cityDb.filter((x) => x.text.match(regex));
    let data = filtered.slice((page - 1) * pageSize, page * pageSize);

    return new Promise<City[]>((resolve) => {
      setTimeout(() => resolve(data), 100);
    });
  }
}

export default (
  <LabelsTopLayout vertical controller={PageController}>
    <LookupField
      label="Select Cities"
      records={m.selectedCities}
      onQueryPage={(params, instance) =>
        instance.getControllerByType(PageController).onQueryPage(params)
      }
      multiple
      infinite
      pageSize={50}
      queryDelay={150}
      minQueryLength={2}
      placeholder="Type at least 2 characters..."
    />
  </LabelsTopLayout>
);

```

## How It Works

With `infinite` enabled, use `onQueryPage` instead of `onQuery`. The callback receives paged query parameters:

```tsx
class PageController extends Controller {
  onQueryPage({ query, pageSize, page }: { query: string; pageSize: number; page: number }) {
    // query - the search text
    // pageSize - number of items per page
    // page - current page number (1-based)
    return fetchFromServer(query, page, pageSize);
  }
}

<LookupField
  onQueryPage={(params, instance) => instance.getControllerByType(PageController).onQueryPage(params)}
  infinite
  pageSize={50}
/>
```

The LookupField monitors scroll position and requests the next page when the user scrolls near the end.

## Configuration

| Property         | Type      | Default | Description                                |
| ---------------- | --------- | ------- | ------------------------------------------ |
| `infinite`       | `boolean` | `false` | Enable infinite scrolling                  |
| `pageSize`       | `number`  | `100`   | Number of items per page                   |
| `queryDelay`     | `number`  | `150`   | Delay (ms) before querying after typing    |
| `minQueryLength` | `number`  | `0`     | Minimum characters required to trigger query |