eis-website/js/api-demo.js

169 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 <li>-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 = `
<div class="api-user-avatar" aria-hidden="true">
${user.name.charAt(0).toUpperCase()}
</div>
<div class="api-user-info">
<h3 class="api-user-name">${user.name}</h3>
<p class="api-user-username">@${user.username}</p>
<ul class="api-user-details">
<li>📧 <a href="mailto:${user.email}">${user.email}</a></li>
<li>🏙️ ${user.address.city}</li>
<li>💼 ${user.company.name}</li>
<li>🌐 <a href="https://${user.website}" target="_blank" rel="noopener noreferrer">${user.website}</a></li>
</ul>
</div>
`;
return li;
}
/**
* Rendert eine Liste von Usern in den DOM
* @param {Array} users
*/
function renderUsers (users) {
userList.innerHTML = '';
if (users.length === 0) {
userList.innerHTML = '<li class="api-no-results">Keine Benutzer gefunden. 🔍</li>';
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();
});