Tutorials Logic
Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

Real World AJAX Examples — Live Search, Infinite Scroll

Example 1: Live Search / Autocomplete

A live search box that queries the server as the user types and displays suggestions in a dropdown - debounced to avoid flooding the server with requests.

Live Search - HTML Structure
<div class="search-wrapper" style="position:relative; max-width:400px;">
  <input type="text" id="live-search" placeholder="Search products..."
         autocomplete="off" class="form-control">
  <ul id="search-results" style="
    position:absolute; top:100%; left:0; right:0;
    background:#fff; border:1px solid #ddd; border-radius:4px;
    list-style:none; margin:0; padding:0; z-index:100; display:none;">
  </ul>
</div>
Live Search - JavaScript
const input = document.getElementById('live-search');
const resultsList = document.getElementById('search-results');
let debounceTimer;
let currentController = null;

input.addEventListener('input', function () {
  const query = this.value.trim();
  clearTimeout(debounceTimer);

  // Cancel any in-flight request
  if (currentController) currentController.abort();

  if (query.length < 2) {
    resultsList.style.display = 'none';
    resultsList.innerHTML = '';
    return;
  }

  debounceTimer = setTimeout(async () => {
    currentController = new AbortController();

    try {
      const res = await fetch(
        `/api/search?q=${encodeURIComponent(query)}`,
        { signal: currentController.signal }
      );
      const items = await res.json();

      if (items.length === 0) {
        resultsList.innerHTML = '<li style="padding:8px 12px;color:#999">No results</li>';
      } else {
        resultsList.innerHTML = items.map(item => `
          <li data-id="${item.id}" style="padding:8px 12px;cursor:pointer;border-bottom:1px solid #eee"
              onmouseover="this.style.background='#f5f5f5'"
              onmouseout="this.style.background=''">
            ${item.name}
          </li>
        `).join('');

        resultsList.querySelectorAll('li[data-id]').forEach(li => {
          li.addEventListener('click', () => {
            input.value = li.textContent.trim();
            resultsList.style.display = 'none';
            console.log('Selected ID:', li.dataset.id);
          });
        });
      }

      resultsList.style.display = 'block';
    } catch (err) {
      if (err.name !== 'AbortError') console.error('Search error:', err);
    }
  }, 300);
});

// Hide results when clicking outside
document.addEventListener('click', e => {
  if (!e.target.closest('.search-wrapper')) {
    resultsList.style.display = 'none';
  }
});

Example 2: Infinite Scroll / Load More

Load additional content when the user scrolls to the bottom of the page - a pattern used by social media feeds and product listings.

Infinite Scroll with IntersectionObserver
let currentPage = 1;
let isLoading = false;
let hasMore = true;

const feed = document.getElementById('post-feed');
const sentinel = document.getElementById('scroll-sentinel'); // empty div at bottom

// IntersectionObserver fires when sentinel enters the viewport
const observer = new IntersectionObserver(async (entries) => {
  if (entries[0].isIntersecting && !isLoading && hasMore) {
    await loadMorePosts();
  }
}, { threshold: 0.1 });

observer.observe(sentinel);

async function loadMorePosts() {
  isLoading = true;
  sentinel.innerHTML = '<div class="spinner">Loading...</div>';

  try {
    const res = await fetch(`/api/posts?page=${currentPage}&limit=10`);
    const { posts, totalPages } = await res.json();

    posts.forEach(post => {
      const article = document.createElement('article');
      article.className = 'post-card';
      article.innerHTML = `
        <h3>${post.title}</h3>
        <p>${post.excerpt}</p>
        <small>By ${post.author} - ${post.date}</small>
      `;
      feed.appendChild(article);
    });

    currentPage++;
    hasMore = currentPage <= totalPages;

    sentinel.innerHTML = hasMore
      ? '' // clear spinner, observer will trigger again
      : '<p style="text-align:center;color:#999">No more posts</p>';

  } catch (err) {
    sentinel.innerHTML = '<p class="text-danger">Failed to load posts</p>';
    console.error(err);
  } finally {
    isLoading = false;
  }
}

// Load first page on startup
loadMorePosts();

Example 3: Real-Time Form Validation

Validate form fields against the server in real time - checking for duplicate emails, weak passwords, or invalid coupon codes as the user fills in the form.

Real-Time Email and Coupon Validation
// Reusable debounced validator
function createValidator(inputEl, feedbackEl, endpoint, paramName, minLength = 3) {
  let timer;

  inputEl.addEventListener('blur', () => validate()); // also validate on blur
  inputEl.addEventListener('input', () => {
    clearTimeout(timer);
    const value = inputEl.value.trim();

    if (value.length < minLength) {
      setFeedback(feedbackEl, '', 'neutral');
      return;
    }

    setFeedback(feedbackEl, 'Checking...', 'neutral');
    timer = setTimeout(() => validate(), 400);
  });

  async function validate() {
    const value = inputEl.value.trim();
    if (value.length < minLength) return;

    try {
      const res = await fetch(`${endpoint}?${paramName}=${encodeURIComponent(value)}`);
      const { valid, message } = await res.json();
      setFeedback(feedbackEl, message, valid ? 'success' : 'error');
      inputEl.dataset.valid = valid;
    } catch {
      setFeedback(feedbackEl, 'Could not validate', 'neutral');
    }
  }
}

function setFeedback(el, message, type) {
  el.textContent = message;
  el.className = `feedback feedback-${type}`;
}

// Initialize validators
createValidator(
  document.getElementById('email'),
  document.getElementById('email-feedback'),
  '/api/validate/email', 'email', 5
);

createValidator(
  document.getElementById('coupon'),
  document.getElementById('coupon-feedback'),
  '/api/validate/coupon', 'code', 4
);

// Prevent form submission if any field is invalid
document.getElementById('register-form').addEventListener('submit', function (e) {
  const fields = this.querySelectorAll('[data-valid]');
  const allValid = Array.from(fields).every(f => f.dataset.valid === 'true');

  if (!allValid) {
    e.preventDefault();
    document.getElementById('form-error').textContent = 'Please fix the errors above.';
  }
});

Example 4: Dynamic Content Loading (Tabs without Page Reload)

Load tab content on demand via AJAX - only fetching data when the user clicks a tab, and caching it so subsequent clicks don't re-fetch.

AJAX Tabs with Caching
// HTML structure expected:
// <div class="tab-nav">
//   <button class="tab-btn active" data-tab="overview" data-url="/api/tabs/overview">Overview</button>
//   <button class="tab-btn" data-tab="reviews" data-url="/api/tabs/reviews">Reviews</button>
//   <button class="tab-btn" data-tab="specs" data-url="/api/tabs/specs">Specs</button>
// </div>
// <div id="tab-content"></div>

const tabCache = {};
const tabContent = document.getElementById('tab-content');

document.querySelectorAll('.tab-btn').forEach(btn => {
  btn.addEventListener('click', async function () {
    const tabId = this.dataset.tab;
    const url = this.dataset.url;

    // Update active state
    document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
    this.classList.add('active');

    // Serve from cache if available
    if (tabCache[tabId]) {
      tabContent.innerHTML = tabCache[tabId];
      return;
    }

    // Show loading state
    tabContent.innerHTML = '<div class="tab-loading"><span class="spinner"></span> Loading...</div>';

    try {
      const res = await fetch(url);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);

      const html = await res.text(); // tabs return HTML fragments
      tabCache[tabId] = html;        // cache for future clicks
      tabContent.innerHTML = html;

    } catch (err) {
      tabContent.innerHTML = `<p class="text-danger">Failed to load tab: ${err.message}</p>`;
    }
  });
});

// Load the default active tab on page load
const defaultTab = document.querySelector('.tab-btn.active');
if (defaultTab) defaultTab.click();

Level Up Your Ajax Skills

Master Ajax with these hand-picked resources

10,000+ learners
Free forever
Updated 2026

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.