Event Handling
Event handling is a way to handle user actions such as clicks, hovers, and inputs.
Event Basics
onclick
<button onclick="alert('Click!')">Click Me</button>
addEventListener
<button id="myBtn">Click Me</button>
<script>
document.getElementById('myBtn').addEventListener('click', function() {
alert('Click!');
});
</script>
Event Types
Mouse Events
<div id="box" style="width: 200px; height: 200px; background: #3498db;">
Hover me
</div>
<script>
const box = document.getElementById('box');
box.addEventListener('mouseover', function() {
this.style.background = '#e74c3c';
});
box.addEventListener('mouseout', function() {
this.style.background = '#3498db';
});
box.addEventListener('click', function() {
this.style.background = '#2ecc71';
});
</script>
Keyboard Events
<input type="text" id="keyboard" placeholder="Ketik sesuatu">
<p id="keyOutput"></p>
<script>
const input = document.getElementById('keyboard');
const output = document.getElementById('keyOutput');
input.addEventListener('keydown', function(e) {
output.textContent = `Key: ${e.key}, Code: ${e.code}`;
});
</script>
Form Events
<form id="myForm">
<input type="text" name="name" placeholder="Name">
<button type="submit">Send</button>
</form>
<script>
document.getElementById('myForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
console.log('Name:', formData.get('name'));
});
</script>
Case Study: Interactive Registration Form
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Interactive Registration Form</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', sans-serif;
background: #f0f2f5;
padding: 2rem;
}
.container {
max-width: 600px;
margin: 0 auto;
}
.card {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #1e3a5f;
margin-bottom: 1.5rem;
text-align: center;
}
.form-group {
margin-bottom: 1.5rem;
}
label {
display: block;
margin-bottom: 0.5rem;
color: #333;
font-weight: 500;
}
input, select {
width: 100%;
padding: 0.8rem;
border: 2px solid #ddd;
border-radius: 4px;
font-size: 1rem;
transition: border-color 0.3s;
}
input:focus, select:focus {
outline: none;
border-color: #3498db;
}
input.valid {
border-color: #2ecc71;
}
input.invalid {
border-color: #e74c3c;
}
.error-message {
color: #e74c3c;
font-size: 0.85rem;
margin-top: 0.5rem;
display: none;
}
.error-message.active {
display: block;
}
.char-count {
text-align: right;
font-size: 0.8rem;
color: #666;
margin-top: 0.3rem;
}
.btn {
width: 100%;
padding: 0.8rem;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
}
.btn:hover {
background: #2980b9;
}
.btn:disabled {
background: #bdc3c7;
cursor: not-allowed;
}
.preview {
margin-top: 1.5rem;
padding: 1rem;
background: #f8f9fa;
border-radius: 4px;
display: none;
}
.preview.active {
display: block;
}
.preview h3 {
color: #1e3a5f;
margin-bottom: 0.5rem;
font-size: 1rem;
}
.preview p {
margin-bottom: 0.3rem;
}
.strength-bar {
height: 5px;
background: #e9ecef;
border-radius: 3px;
margin-top: 0.5rem;
overflow: hidden;
}
.strength-fill {
height: 100%;
width: 0%;
transition: width 0.3s, background 0.3s;
}
.events-log {
margin-top: 1.5rem;
padding: 1rem;
background: #1e3a5f;
color: #2ecc71;
border-radius: 4px;
font-family: monospace;
font-size: 0.8rem;
max-height: 150px;
overflow-y: auto;
}
.events-log p {
margin-bottom: 0.3rem;
}
</style>
</head>
<body>
<div class="container">
<div class="card">
<h1>Interactive Registration Form</h1>
<form id="registrationForm">
<div class="form-group">
<label for="name">Full name</label>
<input type="text" id="name" name="name"
placeholder="Enter your full name" required>
<div class="char-count"><span id="nameCount">0</span>/50</div>
<div class="error-message" id="nameError">Name must be at least 3 characters</div>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email"
placeholder="[email protected]" required>
<div class="error-message" id="emailError">Invalid email</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password"
placeholder="At least 8 characters" required>
<div class="strength-bar">
<div class="strength-fill" id="strengthFill"></div>
</div>
<div class="error-message" id="passwordError">Password at least 8 characters</div>
</div>
<div class="form-group">
<label for="major">Major</label>
<select id="major" name="major" required>
<option value="">Select Major</option>
<option value="cs">Computer Science</option>
<option value="si">Information Systems</option>
<option value="management">Management/option>
<option value="accounting">Accounting/option>
</select>
</div>
<button type="submit" id="submitBtn" disabled>Register</button>
</form>
<div class="preview" id="preview">
<h3>Preview Data</h3>
<p><strong>Name:</strong> <span id="previewName">-</span></p>
<p><strong>Email:</strong> <span id="previewEmail">-</span></p>
<p><strong>Major:</strong> <span id="previewMajor">-</span></p>
</div>
<div class="events-log" id="eventsLog">
<p>Events Log:</p>
</div>
</div>
</div>
<script>
const form = document.getElementById('registrationForm');
const eventsLog = document.getElementById('eventsLog');
const submitBtn = document.getElementById('submitBtn');
// Log events
function logEvent(message) {
const time = new Date().toLocaleTimeString('id-ID');
const p = document.createElement('p');
p.textContent = `[${time}] ${message}`;
eventsLog.prepend(p);
}
// Name validation
const nameInput = document.getElementById('name');
const nameError = document.getElementById('nameError');
const nameCount = document.getElementById('nameCount');
nameInput.addEventListener('input', function() {
const value = this.value;
nameCount.textContent = value.length;
if (value.length >= 3) {
this.classList.remove('invalid');
this.classList.add('valid');
nameError.classList.remove('active');
} else if (value.length > 0) {
this.classList.remove('valid');
this.classList.add('invalid');
nameError.classList.add('active');
} else {
this.classList.remove('valid', 'invalid');
nameError.classList.remove('active');
}
updatePreview();
validateForm();
logEvent(`Input name: "${value}"`);
});
nameInput.addEventListener('focus', function() {
logEvent('Focus on name input');
});
nameInput.addEventListener('blur', function() {
logEvent('Blur from name input');
});
// Email validation
const emailInput = document.getElementById('email');
const emailError = document.getElementById('emailError');
emailInput.addEventListener('input', function() {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (emailRegex.test(this.value)) {
this.classList.remove('invalid');
this.classList.add('valid');
emailError.classList.remove('active');
} else if (this.value.length > 0) {
this.classList.remove('valid');
this.classList.add('invalid');
emailError.classList.add('active');
} else {
this.classList.remove('valid', 'invalid');
emailError.classList.remove('active');
}
updatePreview();
validateForm();
});
// Password strength
const passwordInput = document.getElementById('password');
const passwordError = document.getElementById('passwordError');
const strengthFill = document.getElementById('strengthFill');
passwordInput.addEventListener('input', function() {
const password = this.value;
let strength = 0;
if (password.length >= 8) strength += 25;
if (password.match(/[a-z]/)) strength += 25;
if (password.match(/[A-Z]/)) strength += 25;
if (password.match(/[0-9]/)) strength += 25;
strengthFill.style.width = strength + '%';
if (strength <= 25) {
strengthFill.style.background = '#e74c3c';
} else if (strength <= 50) {
strengthFill.style.background = '#f39c12';
} else if (strength <= 75) {
strengthFill.style.background = '#3498db';
} else {
strengthFill.style.background = '#2ecc71';
}
if (password.length >= 8) {
this.classList.remove('invalid');
this.classList.add('valid');
passwordError.classList.remove('active');
} else if (password.length > 0) {
this.classList.remove('valid');
this.classList.add('invalid');
passwordError.classList.add('active');
} else {
this.classList.remove('valid', 'invalid');
passwordError.classList.remove('active');
}
validateForm();
});
// Program change
const majorSelect = document.getElementById('major');
majorSelect.addEventListener('change', function() {
logEvent(`Major selected: ${this.options[this.selectedIndex].text}`);
updatePreview();
validateForm();
});
// Form submit
form.addEventListener('submit', function(e) {
e.preventDefault();
logEvent('Form disubmit!');
const formData = new FormData(this);
let data = {};
formData.forEach((value, key) => data[key] = value);
alert('Registration successful!\n\n' + JSON.stringify(data, null, 2));
});
// Keyboard events
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
logEvent('Escape key pressed');
}
});
// Helper functions
function validateForm() {
const isNameValid = nameInput.value.length >= 3;
const isEmailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailInput.value);
const isPasswordValid = passwordInput.value.length >= 8;
const isMajorValid = majorSelect.value !== '';
submitBtn.disabled = !(isNameValid && isEmailValid && isPasswordValid && isMajorValid);
}
function updatePreview() {
const preview = document.getElementById('preview');
if (nameInput.value || emailInput.value || majorSelect.value) {
preview.classList.add('active');
document.getElementById('previewName').textContent = nameInput.value || '-';
document.getElementById('previewEmail').textContent = emailInput.value || '-';
document.getElementById('previewMajor').textContent =
majorSelect.value ? majorSelect.options[majorSelect.selectedIndex].text : '-';
} else {
preview.classList.remove('active');
}
}
</script>
</body>
</html>
Everyday Case Study
Case: A developer needs to add hover and click effects.
<div class="card" id="card">
<h3>Hover and Click</h3>
<p>Seret mouse ke sini</p>
</div>
<script>
const card = document.getElementById('card');
card.addEventListener('mouseenter', function() {
this.style.transform = 'scale(1.05)';
});
card.addEventListener('mouseleave', function() {
this.style.transform = 'scale(1)';
});
card.addEventListener('click', function() {
this.style.background = '#3498db';
});
</script>
Best Practices
- addEventListener: More flexible than onclick
- Event delegation: For dynamic elements
- preventDefault: To prevent default behavior
- stopPropagation: To stop event bubbling
- Remove listener: Remove event listeners that are no longer needed
Summary
Event handling allows web applications to respond to user actions. Use addEventListener for more maintainable code.