Skip to content

Search Filter

Live-Suche und Filterung einer Produktliste.

Component HTML

html
<div class="max-w-4xl mx-auto">
  <h2 class="text-2xl font-bold text-gray-900 mb-6">{{title}}</h2>

  <div
    data-island="search-filter"
    data-island-props='{"items": {{items}}}'
  >
    <!-- Search Filter Island rendert hier -->
  </div>
</div>

Island Code

javascript
// islands/search-filter.js
export default class SearchFilterIsland {
  constructor(element, props = {}) {
    this.element = element;
    this.items = props.items || [];
    this.searchTerm = '';
    this.selectedCategory = 'all';
    this.init();
  }

  init() {
    this.render();
    this.attachEvents();
  }

  get filteredItems() {
    return this.items.filter(item => {
      const matchesSearch = item.name.toLowerCase().includes(this.searchTerm.toLowerCase());
      const matchesCategory = this.selectedCategory === 'all' || item.category === this.selectedCategory;
      return matchesSearch && matchesCategory;
    });
  }

  get categories() {
    return ['all', ...new Set(this.items.map(item => item.category))];
  }

  render() {
    const filtered = this.filteredItems;

    this.element.innerHTML = `
      <div class="mb-6 flex gap-4">
        <input
          type="text"
          placeholder="Suche..."
          class="search-input flex-1 px-4 py-2 border border-gray-300 rounded-lg"
          value="${this.searchTerm}"
        />
        <select class="category-select px-4 py-2 border border-gray-300 rounded-lg">
          ${this.categories.map(cat => `
            <option value="${cat}" ${cat === this.selectedCategory ? 'selected' : ''}>
              ${cat === 'all' ? 'Alle Kategorien' : cat}
            </option>
          `).join('')}
        </select>
      </div>

      <div class="text-sm text-gray-600 mb-4">
        ${filtered.length} von ${this.items.length} Produkten
      </div>

      <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        ${filtered.map(item => `
          <div class="p-4 bg-white border border-gray-200 rounded-lg">
            <h3 class="font-semibold text-gray-900">${item.name}</h3>
            <p class="text-sm text-gray-600">${item.category}</p>
            <p class="text-lg font-bold text-blue-600 mt-2">${item.price}</p>
          </div>
        `).join('')}
      </div>

      ${filtered.length === 0 ? '<p class="text-center text-gray-500 mt-8">Keine Produkte gefunden</p>' : ''}
    `;
  }

  attachEvents() {
    this.element.querySelector('.search-input').addEventListener('input', (e) => {
      this.searchTerm = e.target.value;
      this.render();
      this.attachEvents();
    });

    this.element.querySelector('.category-select').addEventListener('change', (e) => {
      this.selectedCategory = e.target.value;
      this.render();
      this.attachEvents();
    });
  }

  destroy() {
    // Cleanup
  }
}

Was du lernst

  • Live Search: Sofortige Filterung bei Eingabe
  • Multiple Filters: Kombination von Such- und Kategorie-Filter
  • Computed Values: Abgeleitete Werte (filteredItems, categories)
  • Performance: useMemo/computed für optimierte Berechnungen

Webmate Studio Component Development Dokumentation