/** * api-demo.js * Fetch & API Demo – jsonplaceholder.typicode.com/users * Lädt Benutzer per fetch(), rendert sie im DOM, mit Fehlerbehandlung & Filterung. */ document.addEventListener('DOMContentLoaded', function () { // ── DOM-Referenzen ──────────────────────────────────────────────────────── const userList = document.getElementById('user-list'); const loadingEl = document.getElementById('api-loading'); const errorEl = document.getElementById('api-error'); const errorMsgEl = document.getElementById('api-error-msg'); const countEl = document.getElementById('user-count'); const searchInput = document.getElementById('api-search'); const btnReload = document.getElementById('btn-reload'); const btnRetry = document.getElementById('btn-retry'); // Nur auf der API-Demo-Seite ausführen if (!userList) return; // Alle geladenen User merken (für Client-seitigen Filter) let allUsers = []; // ── Hilfsfunktionen ─────────────────────────────────────────────────────── /** Zeigt den Lade-Spinner */ function showLoading () { loadingEl.removeAttribute('hidden'); errorEl.setAttribute('hidden', ''); userList.innerHTML = ''; countEl.textContent = ''; if (btnReload) btnReload.disabled = true; } /** Versteckt den Lade-Spinner */ function hideLoading () { loadingEl.setAttribute('hidden', ''); if (btnReload) btnReload.disabled = false; } /** Zeigt eine Fehlermeldung an */ function showApiError (message) { hideLoading(); errorMsgEl.textContent = message; errorEl.removeAttribute('hidden'); countEl.textContent = ''; } /** * Erstellt eine User-Karte als
  • -Element * @param {Object} user – JSON-Objekt aus der API * @returns {HTMLLIElement} */ function createUserCard (user) { const li = document.createElement('li'); li.className = 'api-user-card'; li.innerHTML = `

    ${user.name}

    @${user.username}

    `; return li; } /** * Rendert eine Liste von Usern in den DOM * @param {Array} users */ function renderUsers (users) { userList.innerHTML = ''; if (users.length === 0) { userList.innerHTML = '
  • Keine Benutzer gefunden. 🔍
  • '; countEl.textContent = ''; return; } // DocumentFragment für performantes Einfügen (ein Reflow statt n) const fragment = document.createDocumentFragment(); users.forEach(function (user) { fragment.appendChild(createUserCard(user)); }); userList.appendChild(fragment); countEl.textContent = users.length + ' Benutzer geladen ✅'; } // ── Haupt-Fetch-Funktion ────────────────────────────────────────────────── function loadUsers () { showLoading(); // ① fetch() aufrufen fetch('https://jsonplaceholder.typicode.com/users') // ② Antwort prüfen & als JSON parsen .then(function (response) { if (!response.ok) { throw new Error('HTTP-Fehler: ' + response.status + ' ' + response.statusText); } return response.json(); }) // ③ Daten verarbeiten & im DOM rendern .then(function (users) { console.log('✅ API-Antwort erhalten:', users); console.table(users.map(function (u) { return { Name: u.name, 'E-Mail': u.email, Stadt: u.address.city, Firma: u.company.name }; })); allUsers = users; hideLoading(); renderUsers(allUsers); // Suchfeld zurücksetzen if (searchInput) searchInput.value = ''; }) // ④ Fehlerbehandlung .catch(function (err) { console.error('❌ Fetch-Fehler:', err); showApiError(err.message || 'Unbekannter Fehler. Bitte Internetverbindung prüfen.'); }); } // ── Client-seitiger Filter ──────────────────────────────────────────────── function filterUsers (query) { if (!query.trim()) { renderUsers(allUsers); return; } const q = query.toLowerCase(); const filtered = allUsers.filter(function (user) { return ( user.name.toLowerCase().includes(q) || user.username.toLowerCase().includes(q) || user.address.city.toLowerCase().includes(q) || user.company.name.toLowerCase().includes(q) || user.email.toLowerCase().includes(q) ); }); renderUsers(filtered); } // ── Event Listener ──────────────────────────────────────────────────────── if (btnReload) btnReload.addEventListener('click', loadUsers); if (btnRetry) btnRetry.addEventListener('click', loadUsers); if (searchInput) { searchInput.addEventListener('input', function () { filterUsers(this.value); }); } // ── Beim Seitenaufruf automatisch laden ─────────────────────────────────── loadUsers(); });