The form has novalidate because of a test result: without it, Chrome 1 validated the form itself, showed its own bubble on the data-validate-on-blur postcode (Framework7 572,986 suppresses it only for validate fields), and never fired submit. Now validateInputs() marks all three fields, then the handler posts the order:
try {
const res = await fetch('https://api.example.com/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(order),
});
const body = await res.json();
if (!res.ok) throw new Error(body.message || `HTTP ${res.status}`);
$f7.form.removeFormData('checkout-form');
$store.dispatch('clearCart');
$f7.dialog.alert(`Order ${body.id} is on its way.`, 'Thank you!',
() => $f7router.back());
} catch (err) {
console.log('order failed:', err.name, err.message);
$f7.dialog.alert(err instanceof TypeError
? 'No connection. Your order is saved on this device; try again.'
: err.message, 'Order not placed');
} finally {
$f7.preloader.hide();
}fetch() rejects with a TypeError only when no response arrives; a 4xx answer resolves, so the code checks res.ok. With no order server, the test posted as is (the host does not resolve), then with Playwright 26,280 's page.route() answering 422 and finally 201:
... Failed to load resource: net::ERR_NAME_NOT_RESOLVED order failed: TypeError Failed to fetch ... Failed to load resource: the server responded with a status of 422 (Unprocessable Entity) order failed: Error We do not deliver to postcode 88410 yet.

The 201 showed "Order BN-1042 is on its way." and emptied the cart and the draft. After a failure the draft stays, since form storage also saves on submit. The preloader shown before try blocks double taps. Validate again on the server: anyone can post to your API.