I’m working on a PHP web app where users input data, validate fields, preview images, and then save the data to MySQL. When submitting the form, I encounter the error:
TypeError: Cannot read properties of null (reading ‘value’)
This happens when I try to access form field values. How can I fix this issue?
function populateReviewSection() {
const reviewContent = document.getElementById('reviewContent');
reviewContent.innerHTML = ''; // Clear previous content
// Helper function to format dates (if applicable)
const formatDate = (dateStr) => {
const date = new Date(dateStr);
if (isNaN(date.getTime())) return 'Not provided';
return date.toLocaleDateString(); // You can customize this format as needed
};
// Retrieve form data
const firstname = document.getElementById('firstname').value;
const surname = document.getElementById('surname').value;
const email = document.getElementById('email').value;
const dob = formatDate(document.getElementById('dob').value); // Format DOB
const gender = document.querySelector('input[name="gender"]:checked')?.value || 'Not selected';
const ridersImagePreview = document.getElementById('ridersImagePreview').src;
const ridersImageName = document.getElementById('ridersImageName').textContent || 'No image selected';
// Retrieve fields for GPS address, employment status, and nationality
const gpsAddress = document.getElementById('riders_gpsAddress').value || 'Not provided';
const employmentStatus = document.getElementById('employment_status').value || 'Not selected';
const nationality = document.getElementById('nationality').value || 'Not selected';
const homeTown = document.getElementById('home_town').value || 'Not provided';
const phoneNumber = document.getElementById('phone_number').value || 'Not provided';
const address = document.getElementById('address').value || 'Not provided';
const stationId = document.getElementById('station_id').value || 'Not selected';
// Step 2: Retrieve form data from Step 2
const idCardType = document.getElementById('id_card_type').value || 'Not selected';
const idCardNumber = document.getElementById('id_card_number').value || 'Not provided';
const idCardExpiry = formatDate(document.getElementById('id_card_expiry').value); // Format ID card expiry
const idCardImagePreview = document.getElementById('idCardImagePreview').src;
const idCardBackImagePreview = document.getElementById('idCardBackImagePreview').src;
const isRiderHavingLicense = document.getElementById('isRiderHavingLicense').value || 'Not selected';
const licenseNumber = document.getElementById('license_number').value || 'Not provided';
const licenseExpiryDate = formatDate(document.getElementById('license_expiry_date').value); // Format license expiry
const licenseImagePreview = document.getElementById('licenseImagePreview').src;
const licenseBackImagePreview = document.getElementById('licenseBackImagePreview').src;
// Get values for the radio button groups
const yearsAsRider = document.querySelector('input[name="years_as_rider"]:checked')?.value || 'Not selected';
const ownMotorbike = document.querySelector('input[name="own_motorbike"]:checked')?.value || 'Not selected';
const workingForPay = document.querySelector('input[name="working_for_pay"]:checked')?.value || 'Not selected';
const business_model = document.getElementById('business_model').value || 'Not provided';
const shareBike = document.querySelector('input[name="share_bike"]:checked')?.value || 'Not selected';
// Populate the reviewContent div with the collected data
reviewContent.innerHTML = `
<!-- Rider's Image displayed above the text -->
<div class="image-preview" style="text-align: center; margin-bottom: 20px;">
<h6><strong>Rider's Image</strong></h6>
<img src="${ridersImagePreview}" alt="Rider's Image" style="max-width: 300px; height: auto; display: block; margin-left: auto; margin-right: auto; border-radius: 8px;">
<p><strong>Image Name:</strong> ${ridersImageName}</p>
</div>
<div class="review-section">
<h6><strong>Personal Information</strong></h6>
<table class="table table-bordered">
<tr>
<th>First Name</th>
<td>${firstname}</td>
</tr>
<tr>
<th>Surname</th>
<td>${surname}</td>
</tr>
<tr>
<th>Email</th>
<td>${email}</td>
</tr>
<tr>
<th>Date of Birth</th>
<td>${dob}</td>
</tr>
<tr>
<th>Gender</th>
<td>${gender}</td>
</tr>
</table>
</div>
<div class="review-section">
<h6><strong>Rider's Details</strong></h6>
<table class="table table-bordered">
<tr>
<th>GPS Address</th>
<td>${gpsAddress}</td>
</tr>
<tr>
<th>Employment Status</th>
<td>${employmentStatus}</td>
</tr>
<tr>
<th>Nationality</th>
<td>${nationality}</td>
</tr>
<tr>
<th>Home Town</th>
<td>${homeTown}</td>
</tr>
<tr>
<th>Phone Number</th>
<td>${phoneNumber}</td>
</tr>
<tr>
<th>Address</th>
<td>${address}</td>
</tr>
<tr>
<th>Station</th>
<td>${stationId}</td>
</tr>
</table>
</div>
<div class="review-section">
<h6><strong>ID Card Information</strong></h6>
<table class="table table-bordered">
<tr>
<th>ID Card Type</th>
<td>${idCardType}</td>
</tr>
<tr>
<th>ID Card Number</th>
<td>${idCardNumber}</td>
</tr>
<tr>
<th>ID Card Expiry</th>
<td>${idCardExpiry}</td>
</tr>
<tr>
<th>ID Card Front</th>
<td><img src="${idCardImagePreview}" alt="ID Card Front" style="max-width: 200px; max-height: 200px;"></td>
</tr>
<tr>
<th>ID Card Back</th>
<td><img src="${idCardBackImagePreview}" alt="ID Card Back" style="max-width: 200px; max-height: 200px;"></td>
</tr>
</table>
</div>
<div class="review-section">
<h6><strong>License Information</strong></h6>
<table class="table table-bordered">
<tr>
<th>Has a License</th>
<td>${isRiderHavingLicense}</td>
</tr>
${isRiderHavingLicense === 'Yes' ? `
<tr>
<th>License Number</th>
<td>${licenseNumber}</td>
</tr>
<tr>
<th>License Expiry</th>
<td>${licenseExpiryDate}</td>
</tr>
<tr>
<th>License Front</th>
<td><img src="${licenseImagePreview}" alt="License Front" style="max-width: 200px; max-height: 200px;"></td>
</tr>
<tr>
<th>License Back</th>
<td><img src="${licenseBackImagePreview}" alt="License Back" style="max-width: 200px; max-height: 200px;"></td>
</tr>
` : ''}
</table>
</div>
<div class="review-section">
<h6><strong>Rider's Experience</strong></h6>
<table class="table table-bordered">
<tr>
<th>Number of Years as a Rider</th>
<td>${yearsAsRider} years</td>
</tr>
<tr>
<th>Do you own the motorbike?</th>
<td>${ownMotorbike}</td>
</tr>
<tr>
<th>Are you working for work and pay?</th>
<td>${workingForPay}</td>
</tr>
<tr>
<th>Your business model if not work and pay</th>
<td>${business_model}</td>
</tr>
<tr>
<th>Do you share the bike with another rider?</th>
<td>${shareBike}</td>
</tr>
</table>
</div>
`;
}
// Add a submit button to your HTML in the review step
document.querySelector('#submit-form').addEventListener('click', function(e) {
e.preventDefault();
// Show SweetAlert2 confirmation dialog
Swal.fire({
title: 'Are you sure?',
text: "You want to submit this rider information?",
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes, submit it!'
}).then((result) => {
if (result.isConfirmed) {
// Disable the submit button to prevent double submission
this.disabled = true;
// Show loading state
$(this).html('<i class="fas fa-spinner fa-spin"></i> Submitting...');
// Call the save function
saveRiderData();
}
});
});
// Update the saveRiderData function to properly collect all form data
function saveRiderData() {
// Create a data object instead of FormData
const data = {
firstname: document.getElementById('firstname').value,
surname: document.getElementById('surname').value,
email: document.getElementById('email').value,
dob: document.getElementById('dob').value,
gender: document.querySelector('input[name="gender"]:checked').value,
gpsAddress: document.getElementById('riders_gpsAddress').value,
employmentStatus: document.getElementById('employmentStatus').value,
nationality: document.getElementById('nationality').value,
homeTown: document.getElementById('home_town').value,
phoneNumber: document.getElementById('phone_number').value,
address: document.getElementById('address').value,
stationId: document.getElementById('station_id').value
};
// Handle image files - convert to base64
const promises = [];
// Function to convert file to base64
const fileToBase64 = (file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
};
// Add riders image
const ridersImage = document.getElementById('ridersImage').files[0];
if (ridersImage) {
promises.push(
fileToBase64(ridersImage).then(base64 => {
data.ridersImagePreview = base64;
})
);
}
// Add ID card images
const idCardImage = document.getElementById('id_card_image').files[0];
if (idCardImage) {
promises.push(
fileToBase64(idCardImage).then(base64 => {
data.idCardImagePreview = base64;
})
);
}
const idCardBackImage = document.getElementById('id_card_back_image').files[0];
if (idCardBackImage) {
promises.push(
fileToBase64(idCardBackImage).then(base64 => {
data.idCardBackImagePreview = base64;
})
);
}
// License information
data.isRiderHavingLicense = document.getElementById('isRiderHavingLicense').value;
if (data.isRiderHavingLicense === 'Yes') {
data.licenseNumber = document.getElementById('license_number').value;
data.licenseExpiryDate = document.getElementById('license_expiry_date').value;
const licenseImage = document.getElementById('license_image').files[0];
if (licenseImage) {
promises.push(
fileToBase64(licenseImage).then(base64 => {
data.licenseImagePreview = base64;
})
);
}
const licenseBackImage = document.getElementById('license_back_image').files[0];
if (licenseBackImage) {
promises.push(
fileToBase64(licenseBackImage).then(base64 => {
data.licenseBackImagePreview = base64;
})
);
}
}
// Experience information
data.yearsAsRider = document.querySelector('input[name="years_as_rider"]:checked').value;
data.ownMotorbike = document.querySelector('input[name="own_motorbike"]:checked').value;
data.workingForPay = document.querySelector('input[name="working_for_pay"]:checked').value;
data.businessModel = document.getElementById('business_model').value;
data.shareBike = document.querySelector('input[name="share_bike"]:checked').value;
// Wait for all file conversions to complete
Promise.all(promises)
.then(() => {
// Send the data using fetch
return fetch('../API/save_rider_data.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
})
.then(response => response.json())
.then(data => {
console.log('Response data:', data);
if (data.status === 'success') {
Swal.fire({
icon: 'success',
title: 'Success!',
text: 'Rider information saved successfully!',
timer: 1500
}).then(() => {
window.location.href = 'riders_list.php';
});
} else {
throw new Error(data.message || 'Failed to save rider information');
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
icon: 'error',
title: 'Error',
text: error.message
});
document.querySelector('#submit-form').disabled = false;
document.querySelector('#submit-form').innerHTML = 'Submit';
});
}
<?php
header('Content-Type: application/json');
// Include database connection
require 'connection.php';
// Start transaction
mysqli_begin_transaction($conn);
try {
// Function to handle file upload
function uploadFile($base64String, $uploadPath)
{
if (strpos($base64String, 'data:image') === 0) {
$base64Image = explode(',', $base64String)[1];
$imageData = base64_decode($base64Image);
$fileName = uniqid() . '.jpg';
$filePath = $uploadPath . $fileName;
if (file_put_contents($filePath, $imageData)) {
return $fileName;
}
}
return null;
}
// Validate required fields
$requiredFields = ['firstname', 'surname', 'email', 'dob', 'nationality', 'employment_status', 'phone_number'];
$data = json_decode(file_get_contents('php://input'), true);
foreach ($requiredFields as $field) {
if (empty($data[$field])) {
throw new Exception("Required field $field is missing");
}
}
// Generate unique registration number
$registrationNumber = 'RDR' . date('Y') . sprintf('%06d', rand(1, 999999));
// Insert into Riders table
$stmt = $conn->prepare("INSERT INTO Riders (
registration_number, first_name, surname, home_town, nationality,
employment_status, dob, gender, email, phone_number, gps_address,
address, station_id, user_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->bind_param(
"ssssssssssssii",
$registrationNumber,
$data['firstname'],
$data['surname'],
$data['homeTown'],
$data['nationality'],
$data['employmentStatus'],
$data['dob'],
$data['gender'],
$data['email'],
$data['phoneNumber'],
$data['gpsAddress'],
$data['address'],
$data['stationId'],
$data['userId']
);
$stmt->execute();
$riderId = $stmt->insert_id;
// Upload and save passport picture
if (!empty($data['ridersImagePreview'])) {
$passportPicture = uploadFile($data['ridersImagePreview'], '../uploads/passport_pictures/');
if ($passportPicture) {
$stmt = $conn->prepare("INSERT INTO PassportPictures (rider_id, passport_picture) VALUES (?, ?)");
$stmt->bind_param("is", $riderId, $passportPicture);
$stmt->execute();
}
}
// Insert ID Card information
if (!empty($data['idCardType'])) {
$idCardFront = uploadFile($data['idCardImagePreview'], '../uploads/id_cards/');
$idCardBack = uploadFile($data['idCardBackImagePreview'], '../uploads/id_cards/');
$stmt = $conn->prepare("INSERT INTO IDCards (
rider_id, id_card_type, id_card_number, id_card_expiry,
id_card_front_image, id_card_back_image
) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->bind_param(
"isssss",
$riderId,
$data['idCardType'],
$data['idCardNumber'],
$data['idCardExpiry'],
$idCardFront,
$idCardBack
);
$stmt->execute();
}
// Insert License information
$hasLicense = $data['isRiderHavingLicense'] === 'Yes';
if ($hasLicense) {
$licenseFront = uploadFile($data['licenseImagePreview'], '../uploads/licenses/');
$licenseBack = uploadFile($data['licenseBackImagePreview'], '../uploads/licenses/');
$stmt = $conn->prepare("INSERT INTO Licenses (
rider_id, license_number, license_expiry_date, has_license,
license_front_image, license_back_image
) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->bind_param(
"ississ",
$riderId,
$data['licenseNumber'],
$data['licenseExpiryDate'],
$hasLicense,
$licenseFront,
$licenseBack
);
$stmt->execute();
}
// Insert Rider Experience
$stmt = $conn->prepare("INSERT INTO RiderExperience (
rider_id, years_as_rider, owns_motorbike, works_for_pay, shares_bike
) VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param(
"issss",
$riderId,
$data['yearsAsRider'],
$data['ownMotorbike'],
$data['workingForPay'],
$data['shareBike']
);
$stmt->execute();
// Commit transaction
mysqli_commit($conn);
echo json_encode([
'status' => 'success',
'message' => 'Rider information saved successfully',
'rider_id' => $riderId,
'registration_number' => $registrationNumber
]);
} catch (Exception $e) {
// Rollback transaction on error
mysqli_rollback($conn);
echo json_encode([
'status' => 'error',
'message' => $e->getMessage()
]);
}
// Close database connection
mysqli_close($conn);