AJAX Básico

Integre com APIs externas usando AJAX/Fetch para carregar dados remotos dinamicamente. Suporte completo a debounce, cache, templates customizados e tratamento de erros.

REST Countries API

Busca de países em tempo real usando a API pública REST Countries.

Ver código

HTML

<select id="countries"></select>

JavaScript

const countriesSelect = new VanillaSmartSelect('#countries', {
  placeholder: 'Digite para buscar países...',
  allowClear: true,
  ajax: {
    url: 'https://restcountries.com/v3.1/name',
    delay: 300,
    transport: (params, config) => {
      const searchTerm = params.term || 'brazil';
      const url = `${config.url}/${encodeURIComponent(searchTerm)}`;
      
      const abortController = new AbortController();
      const fetchPromise = fetch(url, {
        signal: abortController.signal
      }).then(response => response.json());
      
      fetchPromise.abort = () => abortController.abort();
      return fetchPromise;
    },
    processResults: (data) => {
      const results = data.map(country => ({
        id: country.cca3,
        text: country.name.common,
        flag: country.flag,
        capital: country.capital?.[0],
        population: country.population
      }));
      return { results };
    }
  },
  templateResult: (item) => {
    return `
      <div style="display: flex; gap: 10px;">
        <span>${item.flag}</span>
        <div>
          <div>${item.text}</div>
          <small>Capital: ${item.capital}</small>
        </div>
      </div>
    `;
  }
});

ViaCEP - Busca de CEP

Busca de endereços brasileiros por CEP usando a API ViaCEP.

Ver código

HTML

<select id="cep"></select>

JavaScript

const cepSelect = new VanillaSmartSelect('#cep', {
  placeholder: 'Digite um CEP para buscar...',
  allowClear: true,
  ajax: {
    url: 'https://viacep.com.br/ws',
    delay: 400,
    transport: (params, config) => {
      const cep = (params.term || '').replace(/\D/g, '');
      if (cep.length < 8) return Promise.resolve([]);
      
      const url = `${config.url}/${cep}/json/`;
      return fetch(url)
        .then(response => response.json())
        .then(data => data.erro ? [] : [data]);
    },
    processResults: (data) => {
      const results = data.map(address => ({
        id: address.cep,
        text: `${address.cep} - ${address.logradouro}`,
        logradouro: address.logradouro,
        bairro: address.bairro,
        localidade: address.localidade,
        uf: address.uf
      }));
      return { results };
    }
  }
});

Busca de Filmes (Simulado)

Exemplo de busca com dados locais simulando uma API de filmes.

Ver código

HTML

<select id="movies"></select>

JavaScript

const moviesSelect = new VanillaSmartSelect('#movies', {
  placeholder: 'Digite para buscar filmes...',
  allowClear: true,
  ajax: {
    delay: 300,
    transport: (params) => {
      return new Promise((resolve) => {
        setTimeout(() => {
          const term = (params.term || '').toLowerCase();
          const filtered = moviesDatabase.filter(movie =>
            movie.title.toLowerCase().includes(term)
          );
          resolve(filtered);
        }, 500);
      });
    },
    processResults: (data) => {
      return {
        results: data.map(movie => ({
          id: movie.id,
          text: movie.title,
          year: movie.year,
          genre: movie.genre,
          rating: movie.rating
        }))
      };
    }
  },
  templateResult: (item) => {
    return `
      <div style="display: flex; justify-content: space-between;">
        <div>
          <div>🎬 ${item.text}</div>
          <small>${item.year} • ${item.genre}</small>
        </div>
        <span style="background: #ffc107; padding: 4px 8px; border-radius: 4px;">
          ⭐ ${item.rating}
        </span>
      </div>
    `;
  }
});

Headers Customizados

Configure headers HTTP customizados, incluindo autenticação Bearer e Content-Type.

Ver código

HTML

<select id="auth-api"></select>

JavaScript

const authSelect = new VanillaSmartSelect('#auth-api', {
  placeholder: 'Buscar dados autenticados...',
  ajax: {
    url: 'https://api.example.com/data',
    delay: 300,
    transport: (params, config) => {
      const abortController = new AbortController();

      const fetchPromise = fetch(config.url, {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer YOUR_TOKEN_HERE',
          'Content-Type': 'application/json',
          'X-Custom-Header': 'CustomValue'
        },
        body: JSON.stringify({
          query: params.term,
          limit: 20
        }),
        signal: abortController.signal
      })
        .then(response => {
          if (!response.ok) throw new Error(`HTTP ${response.status}`);
          return response.json();
        });

      fetchPromise.abort = () => abortController.abort();
      return fetchPromise;
    },
    processResults: (data) => {
      return {
        results: data.results.map(item => ({
          id: item.id,
          text: item.name
        }))
      };
    }
  }
});

Tratamento de Erros

Monitore e trate erros de requisições AJAX usando eventos customizados.

Ver código

HTML

<select id="error-demo"></select>

JavaScript

const errorSelect = new VanillaSmartSelect('#error-demo', {
  placeholder: 'Digite para testar...',
  ajax: {
    url: 'https://api.invalid-domain-example-12345.com/search',
    delay: 300,
    transport: (params, config) => {
      const abortController = new AbortController();

      const fetchPromise = fetch(config.url, {
        signal: abortController.signal
      })
        .then(response => {
          if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
          }
          return response.json();
        });

      fetchPromise.abort = () => abortController.abort();
      return fetchPromise;
    }
  }
});

// Monitorar eventos
const selectElement = document.getElementById('error-demo');

selectElement.addEventListener('vs:ajaxLoading', (e) => {
  console.log('🔄 Carregando...', e.detail);
});

selectElement.addEventListener('vs:ajaxSuccess', (e) => {
  console.log('✅ Sucesso!', e.detail.data);
  alert('Dados carregados com sucesso!');
});

selectElement.addEventListener('vs:ajaxError', (e) => {
  console.error('❌ Erro ao carregar:', e.detail.error);
  alert(`Erro: ${e.detail.error.message}`);
});

Eventos AJAX

Monitore o estado das requisições usando eventos:

JavaScript

// Eventos disponíveis
selectElement.addEventListener('vs:ajaxLoading', (e) => {
  console.log('Carregando...', e.detail);
});

selectElement.addEventListener('vs:ajaxSuccess', (e) => {
  console.log('Sucesso!', e.detail);
});

selectElement.addEventListener('vs:ajaxError', (e) => {
  console.error('Erro:', e.detail);
});

Recursos Implementados

  • ✅ Carregamento assíncrono via fetch API
  • ✅ Debounce automático para evitar requisições excessivas
  • ✅ Transport customizado para controle total das requisições
  • ✅ Busca remota com parâmetros dinâmicos
  • ✅ Indicador de carregamento
  • ✅ Tratamento de erros com mensagens customizadas
  • ✅ Templates customizados para resultados
  • ✅ Suporte a AbortController para cancelar requisições
  • ✅ Headers HTTP customizados (Authorization, Content-Type)
  • ✅ Eventos de sucesso e erro para monitoramento