Session 2.7 – AJAX, XML, and JSON

Module 2: JavaScript & AJAX | Duration: 1 hr

Learning Objectives

By the end of this session, students will be able to:

  • Understand AJAX and asynchronous communication
  • Use XMLHttpRequest and Fetch API for HTTP requests
  • Parse and generate XML data
  • Work with JSON data format
  • Handle API responses and errors
  • Build dynamic web applications with AJAX

Introduction

AJAX (Asynchronous JavaScript and XML) allows web pages to update asynchronously by exchanging data with a server behind the scenes. This means parts of a web page can be updated without reloading the entire page.

Key Insight

AJAX revolutionized web development by enabling smooth, desktop-like user experiences in web applications. Modern frameworks like React, Vue, and Angular all rely heavily on AJAX principles.

Benefits of AJAX
  • Better UX: No full page reloads needed
  • Faster: Only exchange necessary data
  • Reduced load: Less bandwidth usage
  • Real-time: Update data without user action
  • Responsive: Background data loading

AJAX Basics

AJAX is not a programming language but a technique that combines several technologies:

AJAX Components: 1. HTML/CSS - Structure and presentation 2. DOM - Dynamic content updates 3. XML/JSON - Data exchange formats 4. XMLHttpRequest or Fetch API - Async communication 5. JavaScript - Tie everything together
How AJAX Works
  1. An event occurs (button click, page load, timer)
  2. JavaScript creates an XMLHttpRequest/Fetch object
  3. Request is sent to web server
  4. Server processes the request
  5. Server sends response back
  6. JavaScript processes the response
  7. DOM is updated with new content

XMLHttpRequest API

The traditional way to make AJAX requests in JavaScript.

Basic GET Request
// Create XMLHttpRequest object const xhr = new XMLHttpRequest(); // Configure request xhr.open('GET', 'https://api.example.com/data', true); // Set up callback function xhr.onload = function() { if (xhr.status === 200) { console.log('Success:', xhr.responseText); const data = JSON.parse(xhr.responseText); // Use the data } else { console.error('Error:', xhr.status); } }; xhr.onerror = function() { console.error('Request failed'); }; // Send request xhr.send();
POST Request with Data
const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://api.example.com/users', true); // Set headers xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function() { if (xhr.status === 201) { console.log('Created:', xhr.responseText); } }; // Prepare data const data = { name: 'John Doe', email: 'john@example.com' }; // Send request with JSON data xhr.send(JSON.stringify(data));
Tracking Progress
xhr.upload.addEventListener('progress', function(e) { if (e.lengthComputable) { const percentComplete = (e.loaded / e.total) * 100; console.log('Upload:', percentComplete + '%'); } }); xhr.addEventListener('progress', function(e) { if (e.lengthComputable) { const percentComplete = (e.loaded / e.total) * 100; console.log('Download:', percentComplete + '%'); } });

Fetch API

Modern, promise-based API for making HTTP requests. Cleaner and more powerful than XMLHttpRequest.

Basic GET Request
// Simple fetch fetch('https://api.example.com/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); // With async/await async function getData() { try { const response = await fetch('https://api.example.com/data'); const data = await response.json(); console.log(data); } catch (error) { console.error('Error:', error); } }
POST Request
async function createUser(userData) { try { const response = await fetch('https://api.example.com/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(userData) }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); console.log('Success:', data); return data; } catch (error) { console.error('Error:', error); } } // Usage createUser({ name: 'John Doe', email: 'john@example.com' });
All HTTP Methods
// GET fetch('/api/users') .then(r => r.json()) .then(console.log); // POST fetch('/api/users', { method: 'POST', body: JSON.stringify({ name: 'John' }), headers: { 'Content-Type': 'application/json' } }); // PUT (update entire resource) fetch('/api/users/1', { method: 'PUT', body: JSON.stringify({ name: 'John Doe', email: 'john@example.com' }), headers: { 'Content-Type': 'application/json' } }); // PATCH (partial update) fetch('/api/users/1', { method: 'PATCH', body: JSON.stringify({ name: 'Jane Doe' }), headers: { 'Content-Type': 'application/json' } }); // DELETE fetch('/api/users/1', { method: 'DELETE' });
Advanced Fetch Options
fetch('/api/data', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer token123' }, body: JSON.stringify(data), mode: 'cors', // cors, no-cors, same-origin credentials: 'include', // include, same-origin, omit cache: 'no-cache', // default, no-cache, reload, force-cache redirect: 'follow', // follow, error, manual referrerPolicy: 'no-referrer' });

Working with XML

XML (eXtensible Markup Language) is a markup language for storing and transporting data.

XML Structure Example
<?xml version="1.0" encoding="UTF-8"?> <users> <user id="1"> <name>John Doe</name> <email>john@example.com</email> <age>30</age> </user> <user id="2"> <name>Jane Smith</name> <email>jane@example.com</email> <age>28</age> </user> </users>
Parsing XML in JavaScript
// Fetch and parse XML fetch('data.xml') .then(response => response.text()) .then(xmlString => { // Parse XML string const parser = new DOMParser(); const xmlDoc = parser.parseFromString(xmlString, 'text/xml'); // Extract data const users = xmlDoc.querySelectorAll('user'); users.forEach(user => { const id = user.getAttribute('id'); const name = user.querySelector('name').textContent; const email = user.querySelector('email').textContent; const age = user.querySelector('age').textContent; console.log({ id, name, email, age }); }); }); // Creating XML function createXML() { const xmlDoc = document.implementation.createDocument(null, 'users'); const root = xmlDoc.documentElement; const user = xmlDoc.createElement('user'); user.setAttribute('id', '1'); const name = xmlDoc.createElement('name'); name.textContent = 'John Doe'; user.appendChild(name); const email = xmlDoc.createElement('email'); email.textContent = 'john@example.com'; user.appendChild(email); root.appendChild(user); // Convert to string const serializer = new XMLSerializer(); const xmlString = serializer.serializeToString(xmlDoc); console.log(xmlString); }

Working with JSON

JSON (JavaScript Object Notation) is the modern standard for data exchange. It's lightweight, readable, and natively supported by JavaScript.

JSON Structure
{ "users": [ { "id": 1, "name": "John Doe", "email": "john@example.com", "age": 30, "active": true, "roles": ["admin", "user"] }, { "id": 2, "name": "Jane Smith", "email": "jane@example.com", "age": 28, "active": true, "roles": ["user"] } ] }
JSON Methods
// Parse JSON string to object const jsonString = '{"name":"John","age":30}'; const obj = JSON.parse(jsonString); console.log(obj.name); // "John" // Convert object to JSON string const user = { name: 'John Doe', email: 'john@example.com', age: 30 }; const json = JSON.stringify(user); console.log(json); // '{"name":"John Doe","email":"john@example.com","age":30}' // Pretty print JSON const prettyJson = JSON.stringify(user, null, 2); console.log(prettyJson); /* { "name": "John Doe", "email": "john@example.com", "age": 30 } */ // Filtering properties const filtered = JSON.stringify(user, ['name', 'email']); console.log(filtered); // '{"name":"John Doe","email":"john@example.com"}'
Handling Complex JSON
// Nested JSON const data = { users: [ { id: 1, name: 'John', address: { street: '123 Main St', city: 'Boston', country: 'USA' } } ] }; // Access nested data console.log(data.users[0].address.city); // "Boston" // Safe navigation with optional chaining const city = data.users?.[0]?.address?.city; // Working with dates const obj = { name: 'Event', date: new Date() }; const json = JSON.stringify(obj); console.log(json); // Dates become strings const parsed = JSON.parse(json); parsed.date = new Date(parsed.date); // Convert back to Date
XML vs JSON
Aspect XML JSON
Size Larger (verbose) Smaller (compact)
Parsing Slower Faster
Data Types Text only Multiple types
Arrays Not native Native support
Comments Supported Not supported
Use Case Complex documents APIs, web apps

Practical Examples

Example 1: Live Search
<input type="text" id="searchInput" placeholder="Search..."> <div id="results"></div> <script> const searchInput = document.getElementById('searchInput'); const resultsDiv = document.getElementById('results'); // Debounce function function debounce(func, delay) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), delay); }; } // Search function async function search(query) { if (query.length < 2) { resultsDiv.innerHTML = ''; return; } try { const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`); const data = await response.json(); resultsDiv.innerHTML = data.map(item => `<div class="result-item">${item.name}</div>` ).join(''); } catch (error) { console.error('Search failed:', error); } } // Attach debounced search searchInput.addEventListener('input', debounce(function() { search(this.value); }, 300)); </script>
Example 2: Loading Data on Scroll
<div id="content"></div> <script> let page = 1; let loading = false; async function loadMore() { if (loading) return; loading = true; try { const response = await fetch(`/api/posts?page=${page}`); const posts = await response.json(); const content = document.getElementById('content'); posts.forEach(post => { const div = document.createElement('div'); div.className = 'post'; div.innerHTML = ` <h3>${post.title}</h3> <p>${post.content}</p> `; content.appendChild(div); }); page++; } catch (error) { console.error('Load failed:', error); } finally { loading = false; } } // Infinite scroll window.addEventListener('scroll', () => { if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 500) { loadMore(); } }); // Load initial content loadMore(); </script>
Example 3: Form Submission with AJAX
<form id="contactForm"> <input type="text" name="name" required> <input type="email" name="email" required> <textarea name="message" required></textarea> <button type="submit">Send</button> </form> <div id="formMessage"></div> <script> document.getElementById('contactForm').addEventListener('submit', async function(e) { e.preventDefault(); const formData = new FormData(this); const data = Object.fromEntries(formData); const messageDiv = document.getElementById('formMessage'); try { const response = await fetch('/api/contact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const result = await response.json(); if (response.ok) { messageDiv.innerHTML = '<div class="success">Message sent!</div>'; this.reset(); } else { messageDiv.innerHTML = `<div class="error">${result.error}</div>`; } } catch (error) { messageDiv.innerHTML = '<div class="error">Network error</div>'; } }); </script>
Example 4: Real-time Updates
// Poll server for updates async function checkForUpdates() { try { const response = await fetch('/api/updates'); const data = await response.json(); if (data.hasUpdates) { updateUI(data); } } catch (error) { console.error('Update check failed:', error); } } // Poll every 5 seconds setInterval(checkForUpdates, 5000); // Better: Use Server-Sent Events (SSE) const eventSource = new EventSource('/api/updates/stream'); eventSource.onmessage = function(event) { const data = JSON.parse(event.data); updateUI(data); }; eventSource.onerror = function(error) { console.error('SSE error:', error); eventSource.close(); };

Session Summary

Key Points
  • AJAX: Asynchronous communication without page reloads
  • XMLHttpRequest: Traditional API for AJAX requests
  • Fetch API: Modern, promise-based alternative to XHR
  • XML: Structured data format, verbose but flexible
  • JSON: Lightweight data format, native to JavaScript
  • Async/Await: Clean syntax for handling promises
  • Error Handling: Always implement try-catch blocks
Best Practices
  • Prefer Fetch API over XMLHttpRequest for new projects
  • Use JSON instead of XML when possible
  • Always handle errors and edge cases
  • Implement loading states for better UX
  • Debounce frequent requests (search, scroll)
  • Set appropriate timeouts for requests
  • Use async/await for cleaner code
Next Module Preview

In Module 3, we'll dive into PHP basics, learning server-side programming to build dynamic web applications with database integration and form processing.