Autocomplete remoto
Experimente ao vivo
Abrir Autocomplete remoto no Lab →Autocomplete local e remoto
O Autocomplete local recebe options no schema. Um autocomplete remoto não possui options locais: declara um optionsSource e a aplicação consumidora fornece os dados por meio de dataSourceExecutor.
O Lab usa usuários do DummyJSON como endpoint público real. É apenas uma demonstração de integração; em produção a aplicação consumidora é responsável por backend, HTTP, autenticação, autorização e cache.
optionsSource: {sourceId: 'dummyjson-users', minSearchLength: 2}
minSearchLength impede a busca até que dois caracteres sejam digitados. DYONA Form não faz fetch automaticamente.
Busca e resolução
options.search recebe request.input.searchText. Este exemplo chama https://dummyjson.com/users/search com esse texto, limit=10 e os fields necessários para o label.
options.resolve recebe request.input.value. Ele chama https://dummyjson.com/users/<id> para que um ID em initialValues exiba seu label antes de qualquer busca.
Cada request também inclui context.fieldName, context.values e request.signal. Passe o signal para fetch para abortar buscas substituídas e valide response.ok antes de usar a resposta. DYONA Form mostra estados localizados de carregamento e erro.
Informação secundária no dropdown
DyonaDataSourceOption aceita opcionalmente secondaryLabel:
{value: user.id, label: `${user.firstName} ${user.lastName}`, secondaryLabel: user.email}
O dropdown pode mostrar Emily Johnson e abaixo [email protected]. Após selecionar, o input mostra apenas Emily Johnson; secondaryLabel é somente apresentação e o value continua sendo o ID. É genérico para fornecedor + CUIT, cliente + documento, usuário + email ou produto + código.
Exemplo completo
import {useCallback, useMemo} from 'react';
import {DyonaForm, type DyonaDataSourceExecutor, type DyonaDataSourceOption, type DyonaFormSchema} from '@typhonsoftware/dyona-form';
type DummyUser = {id: number; firstName: string; lastName: string; email: string};
type DummyUsersSearchResponse = {users: DummyUser[]};
const initialValues = {customerId: 1};
function mapUserToOption(user: DummyUser): DyonaDataSourceOption {
return {value: user.id, label: `${user.firstName} ${user.lastName}`, secondaryLabel: user.email};
}
export function RemoteCustomerForm() {
const schema = useMemo<DyonaFormSchema>(() => ({
title: 'Seleção de cliente',
tabs: [{id: 'customer', title: 'Cliente', rows: [{columns: [{
name: 'customerId', label: 'Cliente', type: 'autocomplete',
optionsSource: {sourceId: 'dummyjson-users', minSearchLength: 2},
}]}]}],
}), []);
const dataSourceExecutor = useCallback<DyonaDataSourceExecutor>(async (request) => {
if (request.operation === 'options.search') {
const query = new URLSearchParams({q: request.input.searchText, limit: '10', select: 'id,firstName,lastName,email'});
const response = await fetch(`https://dummyjson.com/users/search?${query}`, {signal: request.signal});
if (!response.ok) throw new Error(`A busca no DummyJSON falhou (HTTP ${response.status})`);
const data = await response.json() as DummyUsersSearchResponse;
return {operation: 'options.search', data: data.users.map(mapUserToOption)};
}
const response = await fetch(`https://dummyjson.com/users/${request.input.value}`, {signal: request.signal});
if (!response.ok) throw new Error(`A resolução no DummyJSON falhou (HTTP ${response.status})`);
const user = await response.json() as DummyUser;
return {operation: 'options.resolve', data: mapUserToOption(user)};
}, []);
return <DyonaForm locale="pt" schema={schema} initialValues={initialValues} dataSourceExecutor={dataSourceExecutor} onSubmit={(values) => console.log(values)} />;
}
O ID numérico é preservado de initialValues, por request.input.value, até option.value. A comparação é estrita: não converta o ID para outro tipo. No envio, DYONA Form retorna {customerId: 1}, não o label.