The request
"Let me calculate again after changing the order." A button is a way to express that intention. It should not become a new home for the pricing formula.
Pause: Should clicking calculate save the order, change inventory or take payment? Under our current contract, none of those actions is authorized. It only requests a new quote.
Start with a native action
In your page, create a form with id quote-form, a submit button and a paragraph with id action-status. This isolated experiment explains event flow before we connect real input.
const form = document.querySelector('#quote-form');
const status = document.querySelector('#action-status');
let requests = 0;
form.addEventListener('submit', (event) => {
event.preventDefault();
requests += 1;
status.textContent = `Calculation requested ${requests} times`;
});
The handler is registered now and called later. PreventDefault stops the form's normal navigation, not other event listeners. Submitting the form rather than handling only a button click also covers keyboard submission. A button that must not submit should have type button.
The event's target is where the event originated; currentTarget is where the current listener is attached. Bubbling lets events reach ancestors. Do not stop propagation reflexively: it can break deliberate coordination elsewhere.
Challenge the first implementation
If initialization runs twice, two listeners can respond to one submit. Put listener registration in one startup path. Rendering should update content, not register another copy of the same handler on every calculation.
For a reusable view with a lifecycle, keep a named callback and remove it when that view is destroyed. Anonymous callbacks are fine when registered once for the lifetime of this simple page.
Build it yourself
Replace the counter body with a call to your existing calculation-and-render coordinator. Keep your domain function unchanged. Add a separate Restore example button with type button. Make restoring load the baseline input and explicitly request a render.
Expected evidence
One submit causes one calculation. Pressing Enter behaves like activating Calculate. Restore does not accidentally submit twice. Changing a button label does not change the computed amount.
Change request
The user wants calculation on every keystroke. Identify the consequences before switching to an input event: incomplete intermediate values, repeated announcements and potentially expensive requests. Local arithmetic is cheap; network-backed actions need a different policy. Keep submit-based calculation until the interaction is confirmed.
Check your reasoning
What belongs in the handler? Reading the intention and coordinating established operations. Eligibility, tax and rounding still belong in the tested domain module. A click handler that duplicates those decisions has introduced a second source of truth.