Browser JavaScript and server code run in separate processes. An onclick handler cannot call a Python, PHP, or other server function directly. Give the server operation an HTTP route, then send a POST request from the button with the record identifier.
Last updated: October 9, 2026.
<button type="button" class="approve" data-request-id="42">
Approve
</button>
<p id="status" aria-live="polite"></p>
<script>
document.querySelector('.approve').addEventListener('click', async (event) => {
const button = event.currentTarget;
button.disabled = true;
try {
const response = await fetch('/requests/approve', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({id: Number(button.dataset.requestId)})
});
if (!response.ok) throw new Error('Approval failed');
document.querySelector('#status').textContent = 'Request approved.';
} catch (error) {
document.querySelector('#status').textContent = error.message;
button.disabled = false;
}
});
</script>The route should authenticate the administrator, validate the numeric ID, verify authorization for that record, perform the update transactionally, and return an appropriate HTTP status. Add the framework’s CSRF token mechanism before deploying this pattern.
The template can generate data, not execute server code
A server-side template runs while the response HTML is being built. It can place a record ID in data-request-id, but the rendered page cannot preserve a live reference to the original server function. After delivery, only browser code responds to the click.
MDN’s Fetch API guide shows how to send a POST body and explains that HTTP error responses do not automatically reject the promise. Check response.ok before treating the action as successful.
Use a normal form when JavaScript is unnecessary
For a simple approve or reject action, a small POST form with a submit button can be more robust and works without JavaScript. MDN documents that submit controls send form data to the form action. Use separate button names or routes to distinguish operations.
Never trust the ID because it came from your page; users can modify HTML and requests. Protect the route with authentication, authorization, CSRF validation, and idempotency where repeated clicks matter. Continue with preventing duplicate submissions, passing JavaScript data to PHP, and using Fetch for dependent controls.