← Back to Module

JavaScript Events and Interactivity

CMU422: Fundamentals of Web Design - Session 7

Birmingham Newman University

Lecturer: James Williams

Building responsive user interfaces

3-hour session • 25 slides • 2 interactive tasks

Session Timeline:

  • 10 min: Registration & waiting
  • 20 min: Opening slides
  • 45 min: Task 1
  • 15 min: Break/Catch up
  • 20 min: Secondary slides
  • 45 min: Task 2
  • Remaining: Self-study

Learning Objectives

  • Understand JavaScript event handling
  • Master different types of events
  • Create interactive user interfaces
  • Handle form submissions and validation
  • Build responsive and accessible interactions

What are JavaScript Events?

Events are actions or occurrences that happen in the browser
  • User interactions (clicks, key presses, mouse movements)
  • Browser actions (page load, resize, scroll)
  • Form submissions and input changes
  • Network events (AJAX responses)
// Event example
button.addEventListener('click', function() {
  console.log('Button clicked!');
});

Common Event Types

// Mouse events
'click', 'dblclick', 'mouseenter', 'mouseleave'

// Keyboard events
'keydown', 'keyup', 'keypress'

// Form events
'submit', 'change', 'input', 'focus', 'blur'

// Document events
'load', 'DOMContentLoaded', 'resize', 'scroll'
  • Mouse events for user interactions
  • Keyboard events for text input
  • Form events for data handling
  • Document events for page lifecycle

Event Handling Methods

// Method 1: addEventListener (recommended)
element.addEventListener('click', function(event) {
  console.log('Clicked!');
});

// Method 2: Inline event handlers
<button onclick="handleClick()">Click me</button>

// Method 3: Event properties
element.onclick = function() {
  console.log('Clicked!');
};
  • addEventListener is the modern approach
  • Allows multiple event listeners
  • Better control over event handling

Try It: Interactive DOM Manipulation

Change color:
Click the buttons to manipulate me!

This demo shows DOM manipulation, event handling, and dynamic styling!

The Event Object

element.addEventListener('click', function(event) {
  console.log(event.type); // 'click'
  console.log(event.target); // Element that was clicked
  console.log(event.clientX); // Mouse X position
  console.log(event.clientY); // Mouse Y position
  event.preventDefault(); // Prevent default behavior
  event.stopPropagation(); // Stop event bubbling
});
  • Contains information about the event
  • Provides methods to control event behavior
  • Automatically passed to event handlers

Event Bubbling and Capturing

// Event bubbling (default)
parent.addEventListener('click', function() {
  console.log('Parent clicked');
});

// Event capturing
parent.addEventListener('click', function() {
  console.log('Parent clicked');
}, true); // true enables capturing

// Stop propagation
child.addEventListener('click', function(event) {
  event.stopPropagation();
});
  • Events bubble up from child to parent
  • Capturing goes from parent to child
  • Use stopPropagation() to prevent bubbling

Form Events

const form = document.querySelector('form');

// Form submission
form.addEventListener('submit', function(event) {
  event.preventDefault();
  // Handle form data
});

// Input changes
input.addEventListener('input', function(event) {
  console.log('Input value:', event.target.value);
});

// Focus events
input.addEventListener('focus', function() {
  this.style.borderColor = 'blue';
});
  • submit: Form submission
  • input: Value changes
  • focus/blur: Field focus
  • change: Value confirmed

Keyboard Events

document.addEventListener('keydown', function(event) {
  console.log('Key pressed:', event.key);
  console.log('Key code:', event.code);

  // Check for specific keys
  if (event.key === 'Enter') {
    console.log('Enter pressed!');
  }

  // Check for modifier keys
  if (event.ctrlKey && event.key === 's') {
    event.preventDefault();
    console.log('Save shortcut!');
  }
});
  • keydown: Key pressed down
  • keyup: Key released
  • keypress: Character input
  • Check for specific keys and modifiers

Mouse Events

element.addEventListener('click', function(event) {
  console.log('Click at:', event.clientX, event.clientY);
});

element.addEventListener('mouseenter', function() {
  this.style.backgroundColor = 'yellow';
});

element.addEventListener('mouseleave', function() {
  this.style.backgroundColor = 'white';
});

element.addEventListener('mousemove', function(event) {
  // Track mouse movement
});
  • click: Single click
  • dblclick: Double click
  • mouseenter/mouseleave: Hover effects
  • mousemove: Mouse tracking

Event Delegation

// Instead of adding listeners to each item
const list = document.querySelector('ul');

list.addEventListener('click', function(event) {
  if (event.target.tagName === 'LI') {
    console.log('List item clicked:', event.target.textContent);
  }
});

// Works for dynamically added items too
  • Attach event listener to parent element
  • Use event.target to identify specific elements
  • Efficient for multiple similar elements
  • Works with dynamically added content

Client-Side Form Validation

form.addEventListener('submit', function(event) {
  event.preventDefault();

  const email = document.getElementById('email').value;
  const password = document.getElementById('password').value;

  if (!email.includes('@')) {
    showError('Please enter a valid email');
    return;
  }

  if (password.length < 8) {
    showError('Password must be at least 8 characters');
    return;
  }

  // Form is valid, submit it
  this.submit();
});
  • Validate before form submission
  • Provide immediate user feedback
  • Always validate on server side too
  • Use HTML5 validation attributes

AJAX and Fetch API

// Fetch data from server
fetch('/api/data')
  .then(response => response.json())
  .then(data => {
    console.log('Data received:', data);
    updateUI(data);
  })
  .catch(error => {
    console.error('Error:', error);
  });

// POST data to server
fetch('/api/submit', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(data)
});
  • Fetch API for HTTP requests
  • Promise-based approach
  • Handle success and error cases
  • Update UI with received data

Local Storage

// Store data
localStorage.setItem('username', 'john');
localStorage.setItem('preferences', JSON.stringify({theme: 'dark'}));

// Retrieve data
const username = localStorage.getItem('username');
const preferences = JSON.parse(localStorage.getItem('preferences'));

// Remove data
localStorage.removeItem('username');
localStorage.clear(); // Remove all

// Session storage (cleared when tab closes)
sessionStorage.setItem('temp', 'value');
  • Store data in browser
  • Persists between sessions
  • Limited to strings (use JSON for objects)
  • 5-10MB storage limit

Animation and Transitions

// CSS transitions
element.style.transition = 'all 0.3s ease';
element.style.transform = 'scale(1.1)';

// JavaScript animations
function animate(element, duration) {
  const start = performance.now();
  function update(currentTime) {
    const elapsed = currentTime - start;
    const progress = Math.min(elapsed / duration, 1);
    element.style.opacity = progress;
    if (progress < 1) {
      requestAnimationFrame(update);
    }
  }
  requestAnimationFrame(update);
}
  • CSS transitions for simple animations
  • JavaScript for complex animations
  • Use requestAnimationFrame for smooth animations
  • Consider performance and accessibility

Accessibility Best Practices

  • Use semantic HTML elements
  • Provide keyboard navigation
  • Add ARIA attributes when needed
  • Ensure focus management
  • Test with screen readers
  • Provide alternative text for images
  • Use sufficient color contrast
// Keyboard navigation
element.addEventListener('keydown', function(event) {
  if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault();
    handleClick();
  }
});

// ARIA attributes
element.setAttribute('aria-label', 'Close dialog');
element.setAttribute('role', 'button');

Error Handling

// Try-catch for synchronous code
try {
  const result = riskyOperation();
  console.log(result);
} catch (error) {
  console.error('Error occurred:', error.message);
  showUserFriendlyError();
}

// Promise error handling
fetch('/api/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .catch(error => {
    console.error('Fetch error:', error);
    showErrorMessage(error.message);
  });
  • Handle errors gracefully
  • Provide user-friendly error messages
  • Log errors for debugging
  • Use try-catch and promise error handling

Task 1: Interactive Form

Instructions:

  1. Create a new HTML file called interactive-form.html
  2. Build a registration form with:
    • Name, email, password, and confirm password fields
    • Real-time validation as user types
    • Password strength indicator
    • Submit button with loading state
  3. Add event listeners for:
    • Input validation on blur and input events
    • Form submission with preventDefault
    • Password strength calculation
  4. Use local storage to remember form data
  5. Add visual feedback for validation states

Time: 45 minutes

This task will help you understand form events and validation

Break Time

15 Minutes

Take a break, ask questions, or catch up on the previous task.

Next: Secondary slides and Task 2

Event Handling Best Practices

  • Use addEventListener instead of inline handlers
  • Remove event listeners when elements are destroyed
  • Use event delegation for multiple elements
  • Prevent default behavior when appropriate
  • Handle errors gracefully
  • Consider performance for frequent events
  • Test across different browsers
// Remove event listener
const handler = function() { console.log('clicked'); };
element.addEventListener('click', handler);
element.removeEventListener('click', handler);

// Throttle frequent events
let timeout;
element.addEventListener('scroll', function() {
  clearTimeout(timeout);
  timeout = setTimeout(handleScroll, 100);
});

Performance Considerations

  • Throttle or debounce frequent events
  • Use event delegation for many elements
  • Avoid inline event handlers
  • Remove unused event listeners
  • Use passive event listeners when possible
  • Consider using Intersection Observer for scroll events
// Passive event listener
element.addEventListener('touchstart', handler, { passive: true });

// Intersection Observer
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('visible');
    }
  });
});

Debugging Event Issues

  • Use browser developer tools
  • Check event listener attachment
  • Verify event target and currentTarget
  • Monitor event propagation
  • Check for JavaScript errors
  • Test event timing
// Debug event listeners
element.addEventListener('click', function(event) {
  console.log('Event target:', event.target);
  console.log('Current target:', event.currentTarget);
  console.log('Event phase:', event.eventPhase);
  console.trace('Event call stack');
});

// Monitor all events
const originalAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
  console.log('Adding listener:', type, 'to', this);
  return originalAddEventListener.call(this, type, listener, options);
};

Mobile-Specific Events

// Touch events
element.addEventListener('touchstart', function(event) {
  console.log('Touch started');
  event.preventDefault(); // Prevent default touch behavior
});

element.addEventListener('touchmove', function(event) {
  console.log('Touch moved');
});

element.addEventListener('touchend', function(event) {
  console.log('Touch ended');
});

// Device orientation
window.addEventListener('orientationchange', function() {
  console.log('Orientation changed');
});
  • Touch events for mobile interactions
  • Orientation change events
  • Consider touch targets (minimum 44px)
  • Handle both touch and mouse events

Task 2: Interactive Dashboard

Instructions:

  1. Create a new HTML file called interactive-dashboard.html
  2. Build an interactive dashboard with:
    • Navigation: Tabbed interface with smooth transitions
    • Widgets: Collapsible panels with toggle functionality
    • Charts: Simple data visualization (use CSS or basic canvas)
    • Search: Real-time search with debouncing
    • Settings: Theme toggle and preferences
  3. Implement event handling for:
    • Tab switching with keyboard navigation
    • Widget collapse/expand animations
    • Search input with live filtering
    • Theme switching with local storage
  4. Add accessibility features (ARIA attributes, keyboard support)
  5. Make it responsive for mobile devices

Time: 45 minutes

This task will help you understand complex event handling and UI interactions

Session Summary

  • Events are the foundation of interactive web applications
  • Use modern event handling methods
  • Implement proper form validation
  • Consider accessibility and performance
  • Handle errors gracefully
  • Test across different devices and browsers

Next Session:

JavaScript Advanced Concepts - Functions, objects, and modern JavaScript